mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 02:37:56 +00:00 
			
		
		
		
	Compare commits
	
		
			324 Commits
		
	
	
		
			release/v2
			...
			v2.7.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 08df7ff714 | ||
|   | ad4ac98d1a | ||
|   | 6633a23635 | ||
|   | e398d3cf4b | ||
|   | f53cc82df1 | ||
|   | 3f9edc80e0 | ||
|   | c3a1d84bcd | ||
|   | a34d8eb625 | ||
|   | 6ae42fe206 | ||
|   | 4539bfb53b | ||
|   | dc57a94416 | ||
|   | 68e2d20264 | ||
|   | 6025b7a74e | ||
|   | 3fcf6114c0 | ||
|   | de0c1423af | ||
|   | f4984247d2 | ||
|   | e0b80a2640 | ||
|   | f2c36882be | ||
|   | 3a1e4d66b4 | ||
|   | 6ea62c12c5 | ||
|   | 517b46d275 | ||
|   | 2503cb842e | ||
|   | 3310b7c565 | ||
|   | 2878e2aa25 | ||
|   | 3b7e6da952 | ||
|   | bbf1c61ea8 | ||
|   | e76fedb207 | ||
|   | 4ab026b88c | ||
|   | 06267690fc | ||
|   | db751e31a3 | ||
|   | 49b8664dc0 | ||
|   | 26e54f8433 | ||
|   | a4ebfdc2e9 | ||
|   | 7cf7d011bd | ||
|   | bce53ff61c | ||
|   | 428a2edcdf | ||
|   | ac897e8a8b | ||
|   | 939869948f | ||
|   | 85a4661914 | ||
|   | adce4a8238 | ||
|   | 180d270f9b | ||
|   | 6a44c0a220 | ||
|   | 87c8084c89 | ||
|   | d65d1418a2 | ||
|   | 5bb1a1b68a | ||
|   | 003662508e | ||
|   | bdf577ecbe | ||
|   | 4b1fbf055f | ||
|   | 8b5c9dd5e9 | ||
|   | 02a315ab0d | ||
|   | 1e4d9ea4e8 | ||
|   | 0b1d7e39eb | ||
|   | 4b184bae24 | ||
|   | c483c99802 | ||
|   | 7ea1ccc9d9 | ||
|   | af190e9967 | ||
|   | 80d3dfb89f | ||
|   | 62c6b119c9 | ||
|   | 4ea8aa9958 | ||
|   | 6a30353b3a | ||
|   | b355b41d4f | ||
|   | 19b2afb469 | ||
|   | 7d65da3abc | ||
|   | c25059e2aa | ||
|   | 122a73f35e | ||
|   | a454b56c7a | ||
|   | ae82160c7f | ||
|   | 4d73bbd605 | ||
|   | 13bec235a1 | ||
|   | e6c196cd67 | ||
|   | 6d9a1cac09 | ||
|   | 55a43ed40d | ||
|   | 3a230e4250 | ||
|   | 0a6ee4ea47 | ||
|   | a430ad7e71 | ||
|   | d1c13ad2dd | ||
|   | b837e41569 | ||
|   | 5e39987e36 | ||
|   | 890eb7311a | ||
|   | fc509adf01 | ||
|   | 767331f575 | ||
|   | d26ef6eeba | ||
|   | 8c672f058f | ||
|   | 448563ab06 | ||
|   | 2a22a35e58 | ||
|   | e745d4efe7 | ||
|   | 701e0b50ff | ||
|   | df082a969e | ||
|   | 5e1937ec4f | ||
|   | e679dc7458 | ||
|   | 7e1a962b57 | ||
|   | 8ad2e12f12 | ||
|   | 23d16e619a | ||
|   | 760cad9a14 | ||
|   | 94997a1f9f | ||
|   | 9060fef03d | ||
|   | 2f8eb90c5a | ||
|   | c0d0435efa | ||
|   | 6942de0475 | ||
|   | cce2528ec4 | ||
|   | 3be0fd45d9 | ||
|   | 8b1a80ce09 | ||
|   | 5e12f00558 | ||
|   | 1d534cb974 | ||
|   | a7e9c96f8d | ||
|   | cb3f7a0872 | ||
|   | 6ad434c02f | ||
|   | 62e3ada15c | ||
|   | 2beef2daba | ||
|   | 4b131465fb | ||
|   | cafc243e55 | ||
|   | 5c44134f9d | ||
|   | 8ed86d3582 | ||
|   | d7792f28de | ||
|   | 5a23df748d | ||
|   | e06a42c197 | ||
|   | 702d7df822 | ||
|   | a369f37780 | ||
|   | 46fdf66141 | ||
|   | 9929dd0e5c | ||
|   | bd33ccb870 | ||
|   | bb1383b1f7 | ||
|   | 2d074f455e | ||
|   | 9bc6372a42 | ||
|   | 9d654535a4 | ||
|   | fd8201e961 | ||
|   | 8bbe084640 | ||
|   | ab22a75fc5 | ||
|   | b74a006f0b | ||
|   | c9eeb12491 | ||
|   | e17f6cfd6c | ||
|   | 7b9013b049 | ||
|   | 159bd40563 | ||
|   | db9a184014 | ||
|   | 1ba4bda798 | ||
|   | 40fe54d18a | ||
|   | b705c9b138 | ||
|   | 51868e5bee | ||
|   | 87596762a8 | ||
|   | af686c46bd | ||
|   | 6afd6ea3a6 | ||
|   | 07ec6d990b | ||
|   | 77fe6ed89e | ||
|   | 6b6f29087d | ||
|   | 5da5e3b38e | ||
|   | 7591b8cd44 | ||
|   | 097fe2e436 | ||
|   | c602b81d55 | ||
|   | 2cbbde4904 | ||
|   | 37aa710173 | ||
|   | 4fc7ae5b85 | ||
|   | f933d42354 | ||
|   | 7ffd0bf2ad | ||
|   | a699beda84 | ||
|   | 704a51290e | ||
|   | f9912bb2c9 | ||
|   | 710d807977 | ||
|   | 5fbad76c83 | ||
|   | 8076467b20 | ||
|   | ce1764919f | ||
|   | 44457d0f55 | ||
|   | d869f6bb78 | ||
|   | 40705e01e1 | ||
|   | 60bd8fd2b2 | ||
|   | c36d9157c4 | ||
|   | ceb6a6fc17 | ||
|   | afc8a59267 | ||
|   | c19ce8a92c | ||
|   | d69e773263 | ||
|   | 39ce81dc84 | ||
|   | 17144ed439 | ||
|   | 7a070009b1 | ||
|   | 627c3c49df | ||
|   | 602921827a | ||
|   | d8579d9500 | ||
|   | bc05845015 | ||
|   | f300e64b06 | ||
|   | adde8a2f85 | ||
|   | 149bdefcc0 | ||
|   | 39f694b6f8 | ||
|   | d6d776e806 | ||
|   | ee92e13b15 | ||
|   | daf6acb083 | ||
|   | 1f3ee2a08a | ||
|   | e9b301a242 | ||
|   | 657e6b660a | ||
|   | bd59686006 | ||
|   | e138431304 | ||
|   | d5665e24a1 | ||
|   | a4b28cd8d5 | ||
|   | 54900100c3 | ||
|   | 197952817d | ||
|   | 92b1bcb9ba | ||
|   | 426bcef5ee | ||
|   | 24986190c4 | ||
|   | 1a18c6b295 | ||
|   | 6e72c28b3e | ||
|   | bdda1aff35 | ||
|   | dd138314b9 | ||
|   | 8cd7a99c55 | ||
|   | ed393b08a5 | ||
|   | 93d1681198 | ||
|   | 4bb41f022a | ||
|   | 006ca731f0 | ||
|   | a3e9114882 | ||
|   | 7577693620 | ||
|   | 9f59239318 | ||
|   | c754cbdc31 | ||
|   | ab28e87245 | ||
|   | e71eff25d5 | ||
|   | 672b0d1d00 | ||
|   | 7b3fd5f42a | ||
|   | 280d4f5e41 | ||
|   | b32870d41b | ||
|   | dad8f68f71 | ||
|   | 368ea4e4f3 | ||
|   | 6690aa7cf5 | ||
|   | 33d12a6bad | ||
|   | b1805a9352 | ||
|   | b126f46c35 | ||
|   | faaaf61bf4 | ||
|   | 7448074b5f | ||
|   | 1737486466 | ||
|   | d1a9315b15 | ||
|   | d1eedc02ef | ||
|   | 5355ac822f | ||
|   | 31f496733f | ||
|   | b1b3ee7887 | ||
|   | 06fbace243 | ||
|   | 65295f58ff | ||
|   | a3885b8b1c | ||
|   | 52115100aa | ||
|   | 36c0209961 | ||
|   | fe09ddfb5a | ||
|   | 7ae8f200a4 | ||
|   | 560205b610 | ||
|   | 23106fc89c | ||
|   | fdced9af89 | ||
|   | e7f51b7be1 | ||
|   | 809b4bb79d | ||
|   | 02566e8e0b | ||
|   | ad894aeb17 | ||
|   | f59d3af832 | ||
|   | 16adc66042 | ||
|   | c1a0c0e86d | ||
|   | d3bc539fff | ||
|   | f8c637a0aa | ||
|   | ed511e346f | ||
|   | b48557e907 | ||
|   | 8f2bcc4622 | ||
|   | 7a20fc0423 | ||
|   | 490284c0e0 | ||
|   | 969b675200 | ||
|   | 0f68c74e43 | ||
|   | 8fc1a1bfed | ||
|   | b97635b980 | ||
|   | 0914c1d23c | ||
|   | aed24a0358 | ||
|   | 8e774109af | ||
|   | 4c2ce84b81 | ||
|   | 423b645c18 | ||
|   | c5e73a76b3 | ||
|   | e88b7fddea | ||
|   | 6d39fd2b08 | ||
|   | ff81d899d1 | ||
|   | 62de3cea24 | ||
|   | bab4f4d6e3 | ||
|   | e629220094 | ||
|   | 3754da24a1 | ||
|   | 6594edd8c6 | ||
|   | 7b767ae03f | ||
|   | 80af312318 | ||
|   | d72bb0b831 | ||
|   | d3d446f88e | ||
|   | 3d50837e9e | ||
|   | 5e58797503 | ||
|   | adf08db227 | ||
|   | 2b4417a586 | ||
|   | 3c057bda39 | ||
|   | cc321786f5 | ||
|   | f70c215ed2 | ||
|   | f6c07de827 | ||
|   | 67e52c8e81 | ||
|   | 0b03e32782 | ||
|   | 0a00c39d14 | ||
|   | 81b9da9228 | ||
|   | fcf2976989 | ||
|   | a4757454ef | ||
|   | 21fb969c57 | ||
|   | d1ee91d78d | ||
|   | 70d6373459 | ||
|   | dea728234e | ||
|   | da1e33b09d | ||
|   | 50c0ae1b24 | ||
|   | a75db95a23 | ||
|   | e48250eb5e | ||
|   | 2fd563e4b1 | ||
|   | 001fe7d7cc | ||
|   | 33101f516e | ||
|   | 98c800060b | ||
|   | 0f1ab81817 | ||
|   | 850b26c878 | ||
|   | 119886994e | ||
|   | 15a7d10e5c | ||
|   | 03a7c616f0 | ||
|   | 2f3e802cee | ||
|   | 1b182f8076 | ||
|   | 151bcc9406 | ||
|   | 6c5863d96a | ||
|   | b552d916d6 | ||
|   | 8034e39bed | ||
|   | 709c1d4f6b | ||
|   | 275b10ba20 | ||
|   | a29ddcc9f5 | ||
|   | f8d0f5e06a | ||
|   | c5f70fdda7 | ||
|   | ce54855f3f | ||
|   | f659da3b8e | ||
|   | 96bb22033e | ||
|   | a9d36f2460 | ||
|   | bf7785534d | ||
|   | 31a550514a | ||
|   | 634b079f45 | ||
|   | 99c77c5dd0 | 
							
								
								
									
										35
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,6 +13,7 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - main | ||||
|       - 'release/*' | ||||
|  | ||||
| defaults: | ||||
|   run: | ||||
| @@ -39,6 +40,16 @@ jobs: | ||||
|         registry_user: ucentral | ||||
|         registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} | ||||
|  | ||||
|     - name: Notify on failure via Slack | ||||
|       if: failure() && github.ref == 'refs/heads/main' | ||||
|       uses: rtCamp/action-slack-notify@v2 | ||||
|       env: | ||||
|         SLACK_USERNAME: GitHub Actions failure notifier | ||||
|         SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | ||||
|         SLACK_COLOR: "${{ job.status }}" | ||||
|         SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png | ||||
|         SLACK_TITLE: Docker build failed for OWSec service | ||||
|  | ||||
|   trigger-testing: | ||||
|     if: startsWith(github.ref, 'refs/pull/') | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -67,4 +78,26 @@ jobs: | ||||
|         workflow: ow_docker-compose.yml | ||||
|         token: ${{ secrets.WLAN_TESTING_PAT }} | ||||
|         ref: master | ||||
|         inputs: '{"owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owgwui_version": "${{ env.BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "main", "owprovui_version": "main"}' | ||||
|         inputs: '{"deployment_version": "${{ env.BASE_BRANCH }}", "owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "${{ env.BASE_BRANCH }}", "owanalytics_version": "${{ env.BASE_BRANCH }}", "owsub_version": "${{ env.BASE_BRANCH }}", "microservice": "owsec"}' | ||||
|  | ||||
|   trigger-deploy-to-dev: | ||||
|     runs-on: ubuntu-latest | ||||
|     if: github.ref == 'refs/heads/main' | ||||
|     needs: | ||||
|       - docker | ||||
|     steps: | ||||
|     - name: Checkout actions repo | ||||
|       uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: Telecominfraproject/.github | ||||
|         path: github | ||||
|  | ||||
|     - name: Trigger deployment of the latest version to dev instance and wait for result | ||||
|       uses: ./github/composite-actions/trigger-workflow-and-wait | ||||
|       with: | ||||
|         owner: Telecominfraproject | ||||
|         repo: wlan-testing | ||||
|         workflow: ucentralgw-dev-deployment.yaml | ||||
|         token: ${{ secrets.WLAN_TESTING_PAT }} | ||||
|         ref: master | ||||
|         inputs: '{"force_latest": "true"}' | ||||
|   | ||||
							
								
								
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - main | ||||
|       - 'release/*' | ||||
|     types: [ closed ] | ||||
|  | ||||
| defaults: | ||||
| @@ -16,4 +17,10 @@ jobs: | ||||
|     steps: | ||||
|       - run: | | ||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||
|           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG" | ||||
|  | ||||
|           if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then | ||||
|             echo "PR branch is $PR_BRANCH_TAG, deleting Docker image" | ||||
|             curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG" | ||||
|           else | ||||
|             echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image" | ||||
|           fi | ||||
|   | ||||
							
								
								
									
										46
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| name: Release chart package | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - 'v*' | ||||
|  | ||||
| defaults: | ||||
|   run: | ||||
|     shell: bash | ||||
|  | ||||
| jobs: | ||||
|   helm-package: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     env: | ||||
|       HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||
|       HELM_REPO_USERNAME: ucentral | ||||
|     steps: | ||||
|       - name: Checkout uCentral assembly chart repo | ||||
|         uses: actions/checkout@v2 | ||||
|         with: | ||||
|           path: wlan-cloud-ucentralsec | ||||
|  | ||||
|       - name: Build package | ||||
|         working-directory: wlan-cloud-ucentralsec/helm | ||||
|         run: | | ||||
|           helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0 | ||||
|           helm repo add bitnami https://charts.bitnami.com/bitnami | ||||
|           helm repo update | ||||
|           helm dependency update | ||||
|           mkdir dist | ||||
|           helm package . -d dist | ||||
|  | ||||
|       - name: Generate GitHub release body | ||||
|         working-directory: wlan-cloud-ucentralsec/helm | ||||
|         run: | | ||||
|           pip3 install yq -q | ||||
|           echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:$GITHUB_REF_NAME" > release.txt | ||||
|           echo "Helm charted may be attached to this release" >> release.txt | ||||
|           echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt | ||||
|  | ||||
|       - name: Create GitHub release | ||||
|         uses: softprops/action-gh-release@v1 | ||||
|         with: | ||||
|           body_path: wlan-cloud-ucentralsec/helm/release.txt | ||||
|           files: wlan-cloud-ucentralsec/helm/dist/* | ||||
| @@ -1,5 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.13) | ||||
| project(owsec VERSION 2.5.0) | ||||
| project(owsec VERSION 2.7.0) | ||||
|  | ||||
| set(CMAKE_CXX_STANDARD 17) | ||||
|  | ||||
| @@ -47,13 +47,17 @@ add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT) | ||||
| set(BUILD_SHARED_LIBS 1) | ||||
|  | ||||
| add_definitions(-DTIP_SECURITY_SERVICE="1") | ||||
| add_definitions(-DPOCO_LOG_DEBUG="1") | ||||
|  | ||||
| add_compile_options(-Wall -Wextra) | ||||
| if(ASAN) | ||||
|     add_compile_options(-fsanitize=address) | ||||
|     add_link_options(-fsanitize=address) | ||||
| endif() | ||||
|  | ||||
| set(Boost_USE_STATIC_LIBS OFF) | ||||
| set(Boost_USE_MULTITHREADED ON) | ||||
| set(Boost_USE_STATIC_RUNTIME OFF) | ||||
| find_package(Boost REQUIRED system) | ||||
| find_package(OpenSSL REQUIRED) | ||||
| find_package(ZLIB REQUIRED) | ||||
| find_package(fmt  REQUIRED) | ||||
| find_package(AWSSDK     REQUIRED COMPONENTS sns) | ||||
| find_package(nlohmann_json  REQUIRED) | ||||
| find_package(CppKafka REQUIRED) | ||||
| @@ -72,10 +76,10 @@ add_executable( owsec | ||||
|         src/framework/KafkaTopics.h | ||||
|         src/framework/MicroService.h | ||||
|         src/framework/orm.h | ||||
|         src/framework/RESTAPI_errors.h | ||||
|         src/framework/RESTAPI_protocol.h | ||||
|         src/framework/StorageClass.h | ||||
|         src/framework/uCentral_Protocol.h | ||||
|         src/framework/ow_constants.h | ||||
|         src/framework/MicroServiceErrorHandler.h | ||||
|         src/framework/WebSocketClientNotifications.h | ||||
|         src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp | ||||
|         src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h | ||||
|         src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h | ||||
| @@ -122,12 +126,16 @@ add_executable( owsec | ||||
|         src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h | ||||
|         src/storage/orm_avatar.cpp src/storage/orm_avatar.h | ||||
|         src/SpecialUserHelpers.h | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h) | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h) | ||||
|  | ||||
| if(NOT SMALL_BUILD) | ||||
|     target_link_libraries(owsec PUBLIC | ||||
|             ${Poco_LIBRARIES} ${Boost_LIBRARIES} ${MySQL_LIBRARIES}  ${ZLIB_LIBRARIES} | ||||
|             CppKafka::cppkafka ${AWSSDK_LINK_LIBRARIES} | ||||
|             ${Poco_LIBRARIES} | ||||
|             ${MySQL_LIBRARIES} | ||||
|             ${ZLIB_LIBRARIES} | ||||
|             CppKafka::cppkafka | ||||
|             ${AWSSDK_LINK_LIBRARIES} | ||||
|             fmt::fmt | ||||
|             ) | ||||
|     if(UNIX AND NOT APPLE) | ||||
|         target_link_libraries(owsec PUBLIC PocoJSON) | ||||
|   | ||||
							
								
								
									
										84
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,16 +1,24 @@ | ||||
| FROM alpine:3.15 AS build-base | ||||
| ARG DEBIAN_VERSION=11.4-slim | ||||
| ARG POCO_VERSION=poco-tip-v1 | ||||
| ARG FMTLIB_VERSION=9.0.0 | ||||
| ARG CPPKAFKA_VERSION=tip-v1 | ||||
| ARG JSON_VALIDATOR_VERSION=2.1.0 | ||||
| ARG AWS_SDK_VERSION=1.9.315 | ||||
|  | ||||
| RUN apk add --update --no-cache \ | ||||
| FROM debian:$DEBIAN_VERSION AS build-base | ||||
|  | ||||
| RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||
|     make cmake g++ git \ | ||||
|     unixodbc-dev postgresql-dev mariadb-dev \ | ||||
|     librdkafka-dev boost-dev openssl-dev \ | ||||
|     zlib-dev nlohmann-json \ | ||||
|     curl-dev | ||||
|     libpq-dev libmariadb-dev libmariadbclient-dev-compat \ | ||||
|     librdkafka-dev libboost-all-dev libssl-dev \ | ||||
|     zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev | ||||
|  | ||||
| FROM build-base AS poco-build | ||||
|  | ||||
| ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json | ||||
| RUN git clone https://github.com/stephb9959/poco /poco | ||||
| ARG POCO_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco | ||||
|  | ||||
| WORKDIR /poco | ||||
| RUN mkdir cmake-build | ||||
| @@ -19,10 +27,26 @@ RUN cmake .. | ||||
| RUN cmake --build . --config Release -j8 | ||||
| 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 | ||||
|  | ||||
| ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json | ||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | ||||
| ARG CPPKAFKA_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka | ||||
|  | ||||
| WORKDIR /cppkafka | ||||
| RUN mkdir cmake-build | ||||
| @@ -33,8 +57,10 @@ RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS json-schema-validator-build | ||||
|  | ||||
| ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json | ||||
| RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | ||||
| 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 | ||||
| @@ -45,14 +71,19 @@ RUN make install | ||||
|  | ||||
| FROM build-base AS aws-sdk-cpp-build | ||||
|  | ||||
| ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json | ||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | ||||
| 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 | ||||
| @@ -74,29 +105,30 @@ 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 /owsec | ||||
| RUN mkdir cmake-build | ||||
| WORKDIR /owsec/cmake-build | ||||
| RUN cmake .. \ | ||||
|           -Dcrypto_LIBRARY=/usr/lib/libcrypto.so \ | ||||
|           -DBUILD_SHARED_LIBS=ON | ||||
| RUN cmake .. | ||||
| RUN cmake --build . --config Release -j8 | ||||
|  | ||||
| FROM alpine:3.15 | ||||
| FROM debian:$DEBIAN_VERSION | ||||
|  | ||||
| ENV OWSEC_USER=owsec \ | ||||
|     OWSEC_ROOT=/owsec-data \ | ||||
|     OWSEC_CONFIG=/owsec-data | ||||
|  | ||||
| RUN addgroup -S "$OWSEC_USER" && \ | ||||
|     adduser -S -G "$OWSEC_USER" "$OWSEC_USER" | ||||
| RUN useradd "$OWSEC_USER" | ||||
|  | ||||
| RUN mkdir /openwifi | ||||
| RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ | ||||
|     chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" | ||||
|  | ||||
| RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \ | ||||
|     mariadb-connector-c libpq unixodbc postgresql-client | ||||
| RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||
|     librdkafka++1 gosu gettext ca-certificates bash jq curl wget \ | ||||
|     libmariadb-dev-compat libpq5 unixodbc postgresql-client | ||||
|  | ||||
| COPY readiness_check /readiness_check | ||||
| COPY test_scripts/curl/cli /cli | ||||
| @@ -107,15 +139,17 @@ COPY templates /dist/templates | ||||
| COPY docker-entrypoint.sh / | ||||
| COPY wait-for-postgres.sh / | ||||
| RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | ||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem | ||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt | ||||
|  | ||||
| COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec | ||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/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=poco-build /poco/cmake-build/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=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 | ||||
|  | ||||
| EXPOSE 16001 17001 16101 | ||||
|  | ||||
| ENTRYPOINT ["/docker-entrypoint.sh"] | ||||
|   | ||||
							
								
								
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # Operator Support | ||||
| In order to support multiple tenants and operators, you must prepare the security service to serve | ||||
| customized e-mails and messages. | ||||
|  | ||||
| ## Structure for `templates` | ||||
| Any file in the root of the directory will be used as defaults. The following files must be present: | ||||
| - email_invitation.html/txt : This email message will be sent to a newly added user.  | ||||
| - email_verification.html/txt : This email is sent when an email verification is required. | ||||
| - password_reset.html/txt : This is sent when a pasword reset is requested. | ||||
| - verification_code.html/txt : This is used during MFA when email based. | ||||
| - signup_verification.html/txt : This email is send to a new subscriber who signed up for service. | ||||
| - sub_email_verification.html/txt : This is sent to a subscriber requiring an email verification. | ||||
| - sub_verification_code.html/txt : This is used during MFA when email based for a subscriber. | ||||
| - logo.jpg : The default logo to use in any of these emails. | ||||
|  | ||||
| ## Structure for `wwwassets` | ||||
| Any file in the root of the directory will be used as defaults. The following files must be present: | ||||
| - email_verification_error.html : Used when email verification has failed. | ||||
| - email_verification_success.html : Used when emil verification has succeeded. | ||||
| - invitation_error.html : | ||||
| - invitation_success.html : | ||||
| - password_policy.html : | ||||
| - password_reset.html : | ||||
| - password_reset_success.html : | ||||
| - password_reset_error.html : | ||||
| - signup_verification.html : | ||||
| - signup_verification_error.html : | ||||
| - signup_verification_success.html : | ||||
| - favicon.ico : icon for the application | ||||
| - 404_error.html : your customized 404 page | ||||
| - the_logo : the logo to use. | ||||
|  | ||||
| ## For tenants | ||||
| When creating a tenant/operator, you must create a subdirectory inside each `wwwassets` and `templates` and replicate  | ||||
| all the files that appear at the root level. You need to use the short Operator name (also known as RegistrantId in the API). This means  | ||||
| no spaces, all lowercase characters and numbers. No special characters: 0-9 and a-z.  | ||||
|  | ||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							| @@ -136,7 +136,7 @@ docker run --rm -ti \ | ||||
| This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running | ||||
| in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| openwifi.kafka.group.id = security | ||||
| openwifi.kafka.client.id = security1 | ||||
| openwifi.kafka.enable = true | ||||
| @@ -166,7 +166,7 @@ Here are the parameters for the public interface. The important files are: | ||||
| - `restapi-key.pem` : the key associated with this certificate | ||||
| - `openwifi.restapi.host.0.key.password` : if you key is password protected, you may supply that password here. | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| openwifi.restapi.host.0.backlog = 100 | ||||
| openwifi.restapi.host.0.security = relaxed | ||||
| openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | ||||
| @@ -181,7 +181,7 @@ openwifi.restapi.host.0.key.password = mypassword | ||||
| The private interface is used for service-to-service communication. You can use self-signed certificates here or letsencrypt. The file names are similar  | ||||
| to the filenames used in the previous section. | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| openwifi.internal.restapi.host.0.backlog = 100 | ||||
| openwifi.internal.restapi.host.0.security = relaxed | ||||
| openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | ||||
| @@ -196,7 +196,7 @@ openwifi.internal.restapi.host.0.key.password = mypassword | ||||
| Here are other important values you must set. | ||||
|  | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| openwifi.system.data = $OWSEC_ROOT/data | ||||
| openwifi.system.uri.private = https://localhost:17001 | ||||
| openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001 | ||||
| @@ -221,7 +221,8 @@ an SMS provider must be configured. At present time, 2 providers are supported: | ||||
| #### AWS SMS | ||||
| For SNS you must create an IAM ID that has sns:sendmessage rights.   | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| smssender.enabled = true | ||||
| smssender.provider = aws | ||||
| smssender.aws.secretkey = *************************************** | ||||
| smssender.aws.accesskey = *************************************** | ||||
| @@ -231,7 +232,8 @@ smssender.aws.region = ************** | ||||
| #### Twilio | ||||
| For Twilio, you must provide the following | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| smssender.enabled = true | ||||
| smssender.provider = twilio | ||||
| smssender.twilio.sid = *********************** | ||||
| smssender.twilio.token = ********************** | ||||
| @@ -243,7 +245,8 @@ smssender.twilio.phonenumber = +18888888888 | ||||
| with GMail and AWS SES. For each, you must obtain the proper credentials and insert them in this configuration as well | ||||
| as the proper mail host. | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| mailer.enabled = true | ||||
| mailer.hostname = smtp.gmail.com | ||||
| mailer.username = ************************ | ||||
| mailer.password = ************************ | ||||
| @@ -254,10 +257,10 @@ mailer.templates = $OWSEC_ROOT/templates | ||||
| ``` | ||||
|  | ||||
| #### Google Authenticator | ||||
| In order to use the Google Time-based One-Time Password (TOTP), the user must down load the Goole Authenticator  | ||||
| In order to use the Google Time-based One-Time Password (TOTP), the user must download the Google Authenticator  | ||||
| on any other app that support the TOTP protocol. You should include the following in your configuration | ||||
|  | ||||
| ```asm | ||||
| ``` | ||||
| totp.issuer = OrgName | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #!/bin/sh | ||||
| #!/bin/bash | ||||
| set -e | ||||
|  | ||||
| if [ "$SELFSIGNED_CERTS" = 'true' ]; then | ||||
|     update-ca-certificates | ||||
| fi | ||||
|  | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; then | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||
|   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \ | ||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ | ||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ | ||||
| @@ -23,6 +23,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; t | ||||
|   SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17001"} \ | ||||
|   SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16001"} \ | ||||
|   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ | ||||
|   SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \ | ||||
|   SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ | ||||
|   SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ | ||||
|   SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \ | ||||
| @@ -42,6 +43,10 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; t | ||||
|   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ | ||||
|   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ | ||||
|   KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ | ||||
|   KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \ | ||||
|   KAFKA_SSL_CERTIFICATE_LOCATION=${KAFKA_SSL_CERTIFICATE_LOCATION:-""} \ | ||||
|   KAFKA_SSL_KEY_LOCATION=${KAFKA_SSL_KEY_LOCATION:-""} \ | ||||
|   KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \ | ||||
|   DOCUMENT_POLICY_ACCESS=${DOCUMENT_POLICY_ACCESS:-"\$OWSEC_ROOT/persist/wwwassets/access_policy.html"} \ | ||||
|   DOCUMENT_POLICY_PASSWORD=${DOCUMENT_POLICY_PASSWORD:-"\$OWSEC_ROOT/persist/wwwassets/password_policy.html"} \ | ||||
|   STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ | ||||
| @@ -80,7 +85,7 @@ if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then | ||||
|     if [ "$RUN_CHOWN" = 'true' ]; then | ||||
|       chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" | ||||
|     fi | ||||
|     exec su-exec "$OWSEC_USER" "$@" | ||||
|     exec gosu "$OWSEC_USER" "$@" | ||||
| fi | ||||
|  | ||||
| exec "$@" | ||||
|   | ||||
							
								
								
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,3 @@ | ||||
| *.swp | ||||
| Chart.lock | ||||
| charts/ | ||||
|   | ||||
| @@ -70,8 +70,8 @@ The following table lists the configurable parameters of the chart and their def | ||||
| | persistence.size | string | Defines PV size | `'10Gi'` | | ||||
| | public_env_variables | hash | Defines list of environment variables to be passed to the Security | | | ||||
| | configProperties | hash | Configuration properties that should be passed to the application in `owsec.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | | | ||||
| | certs | hash | Defines files (keys and certificates) that should be passed to the Security (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted) |  | | ||||
|  | ||||
| | existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` | | ||||
| | certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. |  | | ||||
|  | ||||
| Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| {{- $root := . -}} | ||||
| {{- $storageType := index .Values.configProperties "storage.type" -}} | ||||
| --- | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| @@ -46,6 +47,39 @@ spec: | ||||
|             - -timeout | ||||
|             - 600s | ||||
|  | ||||
| {{- if eq $storageType "postgresql" }} | ||||
|         - name: wait-postgres | ||||
|           image: "{{ .Values.images.owsec.repository }}:{{ .Values.images.owsec.tag }}" | ||||
|           imagePullPolicy: {{ .Values.images.owsec.pullPolicy }} | ||||
|           command: | ||||
|             - /wait-for-postgres.sh | ||||
|             - {{ index .Values.configProperties "storage.type.postgresql.host" }} | ||||
|             - echo | ||||
|             - "PostgreSQL is ready" | ||||
|           env: | ||||
|             - name: KUBERNETES_DEPLOYED | ||||
|               value: "{{ now }}" | ||||
|           {{- range $key, $value := .Values.public_env_variables }} | ||||
|             - name: {{ $key }} | ||||
|               value: {{ $value | quote }} | ||||
|           {{- end }} | ||||
|           {{- range $key, $value := .Values.secret_env_variables }} | ||||
|             - name: {{ $key }} | ||||
|               valueFrom: | ||||
|                 secretKeyRef: | ||||
|                   name: {{ include "owsec.fullname" $root }}-env | ||||
|                   key: {{ $key }} | ||||
|           {{- end }} | ||||
|           volumeMounts: | ||||
|           {{- range .Values.volumes.owsec }} | ||||
|           - name: {{ .name }} | ||||
|             mountPath: {{ .mountPath }} | ||||
|             {{- if .subPath }} | ||||
|             subPath: {{ .subPath }} | ||||
|             {{- end }} | ||||
|           {{- end }} | ||||
| {{- end }} | ||||
|  | ||||
|       containers: | ||||
|  | ||||
|         - name: owsec | ||||
|   | ||||
| @@ -9,7 +9,7 @@ fullnameOverride: "" | ||||
| images: | ||||
|   owsec: | ||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||
|     tag: v2.5.2 | ||||
|     tag: v2.7.0 | ||||
|     pullPolicy: Always | ||||
| #    regcred: | ||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||
| @@ -71,7 +71,7 @@ volumes: | ||||
|       mountPath: /owsec-data/certs | ||||
|       volumeDefinition: | | ||||
|         secret: | ||||
|           secretName: {{ include "owsec.fullname" . }}-certs | ||||
|           secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owsec.fullname" . }}-certs{{ end }} | ||||
|     # Change this if you want to use another volume type | ||||
|     - name: persist | ||||
|       mountPath: /owsec-data/persist | ||||
| @@ -92,7 +92,7 @@ resources: {} | ||||
|   #  memory: 128Mi | ||||
|  | ||||
| securityContext: | ||||
|   fsGroup: 101 | ||||
|   fsGroup: 1000 | ||||
|  | ||||
| nodeSelector: {} | ||||
|  | ||||
| @@ -167,6 +167,10 @@ configProperties: | ||||
|   openwifi.kafka.brokerlist: localhost:9092 | ||||
|   openwifi.kafka.auto.commit: false | ||||
|   openwifi.kafka.queue.buffering.max.ms: 50 | ||||
|   openwifi.kafka.ssl.ca.location: "" | ||||
|   openwifi.kafka.ssl.certificate.location: "" | ||||
|   openwifi.kafka.ssl.key.location: "" | ||||
|   openwifi.kafka.ssl.key.password: "" | ||||
|   # Storage | ||||
|   storage.type: sqlite # (sqlite|postgresql|mysql|odbc) | ||||
|   ## SQLite | ||||
| @@ -224,6 +228,9 @@ configProperties: | ||||
|   storage.type.mysql.username: stephb | ||||
|   storage.type.mysql.password: snoopy99 | ||||
|  | ||||
| # NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr | ||||
| existingCertsSecret: "" | ||||
|  | ||||
| certs: | ||||
|   # restapi-ca.pem: "" | ||||
|   # restapi-cert.pem: "" | ||||
|   | ||||
| @@ -66,6 +66,7 @@ components: | ||||
|                   - 11    # BAD_MFA_TRANSACTION | ||||
|                   - 12    # MFA_FAILURE | ||||
|                   - 13    # SECURITY_SERVICE_UNREACHABLE | ||||
|                   - 14    # CANNOT REFRESH TOKEN | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
| @@ -120,6 +121,15 @@ components: | ||||
|         userId: support@example.com | ||||
|         password: support | ||||
|  | ||||
|     WebTokenRefreshRequest: | ||||
|       type: object | ||||
|       properties: | ||||
|         userId: | ||||
|           type: string | ||||
|           default: support@example.com | ||||
|         refresh_token: | ||||
|           type: string | ||||
|  | ||||
|     WebTokenResult: | ||||
|       description: Login and Refresh Tokens to be used in subsequent API calls. | ||||
|       type: object | ||||
| @@ -355,6 +365,9 @@ components: | ||||
|           format: int64 | ||||
|         userTypeProprietaryInfo: | ||||
|           $ref: '#/components/schemas/UserLoginLoginExtensions' | ||||
|         signupUUID: | ||||
|           type: string | ||||
|           format: uuid | ||||
|  | ||||
|     UserList: | ||||
|       type: object | ||||
| @@ -733,6 +746,12 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: grant_type | ||||
|           schema: | ||||
|             type: string | ||||
|             example: refresh_token | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User id and password | ||||
|         required: true | ||||
| @@ -742,6 +761,7 @@ paths: | ||||
|               oneOf: | ||||
|                 - $ref: '#/components/schemas/WebTokenRequest' | ||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||
|                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: successful operation | ||||
| @@ -791,6 +811,12 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: grant_type | ||||
|           schema: | ||||
|             type: string | ||||
|             example: refresh_token | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User id and password | ||||
|         required: true | ||||
| @@ -800,6 +826,7 @@ paths: | ||||
|               oneOf: | ||||
|                 - $ref: '#/components/schemas/WebTokenRequest' | ||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||
|                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: successful operation | ||||
| @@ -920,6 +947,16 @@ paths: | ||||
|             type: string | ||||
|             example: id1,id2,id3,id4,id5 | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: nameSearch | ||||
|           schema: | ||||
|             type: string | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: emailSearch | ||||
|           schema: | ||||
|             type: string | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserList' | ||||
| @@ -966,6 +1003,16 @@ paths: | ||||
|             type: string | ||||
|             example: id1,id2,id3,id4,id5 | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: nameSearch | ||||
|           schema: | ||||
|             type: string | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: emailSearch | ||||
|           schema: | ||||
|             type: string | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserList' | ||||
| @@ -1064,6 +1111,18 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: forgotPassword | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: resetMFA | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User details (some fields are ignored during update) | ||||
|         content: | ||||
| @@ -1168,6 +1227,18 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: forgotPassword | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: resetMFA | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User details (some fields are ignored during update) | ||||
|         content: | ||||
| @@ -1465,8 +1536,8 @@ paths: | ||||
|           schema: | ||||
|             type: integer | ||||
|             format: int64 | ||||
|           required: required | ||||
|             example: 1,2,3 | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           description: Succesful posting of response. | ||||
| @@ -1484,6 +1555,87 @@ paths: | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|  | ||||
|   /signup: | ||||
|     post: | ||||
|       tags: | ||||
|         - Subscriber Registration | ||||
|       summary: This call allows a new subscriber to register themselves and their devices. | ||||
|       operationId: postSignup | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: email | ||||
|           schema: | ||||
|             type: string | ||||
|             format: email | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: signupUUID | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - Subscriber Registration | ||||
|       summary: modify the signup command in play | ||||
|       operationId: modifySignup | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: signupUUID | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: operation | ||||
|           schema: | ||||
|             type: string | ||||
|             enum: | ||||
|               - cancel | ||||
|               - success | ||||
|               - inprogress | ||||
|               - failed | ||||
|               - poll | ||||
|               - emailVerified | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               type: object | ||||
|               properties: | ||||
|                 reason: | ||||
|                   type: string | ||||
|                 time: | ||||
|                   type: integer | ||||
|                   format: int64 | ||||
|                 errorCode: | ||||
|                   type: integer | ||||
|                   format: int32 | ||||
|         required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|  | ||||
|  | ||||
|   ######################################################################################### | ||||
|   ## | ||||
|   ## These are endpoints that all services in the uCentral stack must provide | ||||
|   | ||||
| @@ -36,6 +36,7 @@ openwifi.system.data = $OWSEC_ROOT/data | ||||
| openwifi.system.uri.private = https://localhost:17001 | ||||
| openwifi.system.uri.public = https://local.dpaas.arilia.com:16001 | ||||
| openwifi.system.uri.ui = https://ucentral-ui.arilia.com | ||||
| openwifi.security.restapi.disable = false | ||||
| openwifi.system.commandchannel = /tmp/app.ucentralsec | ||||
| openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem | ||||
| openwifi.service.key.password = mypassword | ||||
| @@ -82,6 +83,11 @@ openwifi.kafka.enable = true | ||||
| openwifi.kafka.brokerlist = a1.arilia.com:9092 | ||||
| openwifi.kafka.auto.commit = false | ||||
| openwifi.kafka.queue.buffering.max.ms = 50 | ||||
| openwifi.kafka.ssl.ca.location = | ||||
| openwifi.kafka.ssl.certificate.location = | ||||
| openwifi.kafka.ssl.key.location = | ||||
| openwifi.kafka.ssl.key.password = | ||||
|  | ||||
| openwifi.document.policy.access = /wwwassets/access_policy.html | ||||
| openwifi.document.policy.password = /wwwassets/password_policy.html | ||||
| openwifi.avatar.maxsize = 2000000 | ||||
|   | ||||
| @@ -36,6 +36,7 @@ openwifi.system.data = ${SYSTEM_DATA} | ||||
| openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE} | ||||
| openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC} | ||||
| openwifi.system.uri.ui = ${SYSTEM_URI_UI} | ||||
| openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE} | ||||
| openwifi.system.commandchannel = /tmp/app.ucentralsec | ||||
| openwifi.service.key = ${SERVICE_KEY} | ||||
| openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} | ||||
| @@ -82,6 +83,10 @@ openwifi.kafka.enable = ${KAFKA_ENABLE} | ||||
| openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST} | ||||
| openwifi.kafka.auto.commit = false | ||||
| openwifi.kafka.queue.buffering.max.ms = 50 | ||||
| openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION} | ||||
| openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION} | ||||
| openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION} | ||||
| openwifi.kafka.ssl.key.password = ${KAFKA_SSL_KEY_PASSWORD} | ||||
|  | ||||
| openwifi.document.policy.access = ${DOCUMENT_POLICY_ACCESS} | ||||
| openwifi.document.policy.password = ${DOCUMENT_POLICY_PASSWORD} | ||||
|   | ||||
| @@ -18,6 +18,7 @@ namespace OpenWifi { | ||||
|             CREATE | ||||
|         }; | ||||
| /* | ||||
|  *  0) You can only delete yourself if you are a subscriber | ||||
|     1) You cannot delete yourself | ||||
|     2) If you are root, you can do anything. | ||||
|     3) You can do anything to yourself | ||||
| @@ -30,6 +31,11 @@ namespace OpenWifi { | ||||
|  | ||||
|  */ | ||||
|         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { | ||||
|  | ||||
|             // rule 0 | ||||
|             if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE) | ||||
|                 return true; | ||||
|  | ||||
|             //  rule 1 | ||||
|             if(User.id == Target.id && Op==DELETE) | ||||
|                 return false; | ||||
|   | ||||
| @@ -5,25 +5,30 @@ | ||||
| #include "ActionLinkManager.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     int ActionLinkManager::Start() { | ||||
|         poco_information(Logger(),"Starting..."); | ||||
|         if(!Running_) | ||||
|             Thr_.start(*this); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     void ActionLinkManager::Stop() { | ||||
|         poco_information(Logger(),"Stopping..."); | ||||
|         if(Running_) { | ||||
|             Running_ = false; | ||||
|             Thr_.wakeUp(); | ||||
|             Thr_.join(); | ||||
|         } | ||||
|         poco_information(Logger(),"Stopped..."); | ||||
|     } | ||||
|  | ||||
|     void ActionLinkManager::run() { | ||||
|         Running_ = true ; | ||||
|         Utils::SetThreadName("action-mgr"); | ||||
|  | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(2000); | ||||
| @@ -48,39 +53,63 @@ namespace OpenWifi { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD || | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL || | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) && | ||||
|                         (OpenWifi::Now()-i.created)>(24*60*60)) { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 switch(i.action) { | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||
|                                 Logger().information(Poco::format("Send password reset link to %s",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) { | ||||
|                                 poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||
|                                 Logger().information(Poco::format("Send email verification link to %s",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) { | ||||
|                                 poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) { | ||||
|                                 poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: { | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||
|                                 Logger().information(Poco::format("Send subscriber password reset link to %s",UInfo.email)); | ||||
|                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                                 poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: { | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||
|                                 Logger().information(Poco::format("Send subscriber email verification link to %s",UInfo.email)); | ||||
|                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                                 poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: { | ||||
|                         auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                         if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                             poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email)); | ||||
|                         } | ||||
|                         StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|   | ||||
| @@ -12,21 +12,14 @@ namespace OpenWifi { | ||||
|     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||
|     public: | ||||
|  | ||||
| /*        enum Actions { | ||||
|             FORGOT_PASSWORD, | ||||
|             VERIFY_EMAIL, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_VERIFY_EMAIL | ||||
|         }; | ||||
| */ | ||||
|         static ActionLinkManager * instance() { | ||||
|             static auto * instance_ = new ActionLinkManager; | ||||
|             static auto instance_ = new ActionLinkManager; | ||||
|             return instance_; | ||||
|         } | ||||
|  | ||||
|         int Start() final; | ||||
|         void Stop() final; | ||||
|         void run(); | ||||
|         void run() final; | ||||
|  | ||||
|     private: | ||||
|         Poco::Thread        Thr_; | ||||
|   | ||||
| @@ -8,18 +8,21 @@ | ||||
|  | ||||
| #include <ctime> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/KafkaTopics.h" | ||||
|  | ||||
| #include "Poco/Net/OAuth20Credentials.h" | ||||
| #include "Poco/JWT/Token.h" | ||||
| #include "Poco/JWT/Signer.h" | ||||
| #include "Poco/StringTokenizer.h" | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "AuthService.h" | ||||
| #include "framework/KafkaTopics.h" | ||||
|  | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "MFAServer.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -42,32 +45,31 @@ namespace OpenWifi { | ||||
| 		return 1;	// some compilers complain... | ||||
| 	} | ||||
|  | ||||
|     static const std::string DefaultPassword_8_u_l_n_1{"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\.\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"}; | ||||
|  | ||||
|     int AuthService::Start() { | ||||
| 		Signer_.setRSAKey(MicroService::instance().Key()); | ||||
| 		Signer_.addAllAlgorithms(); | ||||
| 		Logger().notice("Starting..."); | ||||
|         poco_information(Logger(),"Starting..."); | ||||
|         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); | ||||
|         RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600); | ||||
|         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); | ||||
|  | ||||
|         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||
|         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||
|         AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||
|         PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1); | ||||
|  | ||||
|         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||
|         SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html"); | ||||
|         SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html"); | ||||
|         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1); | ||||
|         SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html"); | ||||
|         SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html"); | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     void AuthService::Stop() { | ||||
| 		Logger().notice("Stopping..."); | ||||
|         poco_information(Logger(),"Stopping..."); | ||||
|         poco_information(Logger(),"Stopped..."); | ||||
|     } | ||||
|  | ||||
| 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard	Guard(Mutex_); | ||||
|         Expired = false; | ||||
|     bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) { | ||||
|         try { | ||||
|             std::string CallToken; | ||||
|             Poco::Net::OAuth20Credentials Auth(Request); | ||||
| @@ -75,7 +77,88 @@ namespace OpenWifi { | ||||
|                 CallToken = Auth.getBearerToken(); | ||||
|             } | ||||
|  | ||||
|             if (CallToken.empty()) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) { | ||||
|                 auto now = OpenWifi::Now(); | ||||
|  | ||||
|                 //  Create a new token | ||||
|                 auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM); | ||||
|                 auto NewRefreshToken = RefreshToken; | ||||
|                 if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) { | ||||
|                     NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM); | ||||
|                     UI.webtoken.lastRefresh_ = now; | ||||
|                 } | ||||
|  | ||||
|                 StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ ); | ||||
|                 UI.webtoken.access_token_ = NewToken; | ||||
|                 UI.webtoken.refresh_token_ = NewRefreshToken; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|  | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) { | ||||
|         try { | ||||
|             std::string CallToken; | ||||
|             Poco::Net::OAuth20Credentials Auth(Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 CallToken = Auth.getBearerToken(); | ||||
|             } | ||||
|  | ||||
|             if (CallToken.empty()) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) { | ||||
|                 auto now = OpenWifi::Now(); | ||||
|  | ||||
|                 //  Create a new token | ||||
|                 auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM); | ||||
|                 auto NewRefreshToken = RefreshToken; | ||||
|                 if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) { | ||||
|                     NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM); | ||||
|                     UI.webtoken.lastRefresh_ = now; | ||||
|                 } | ||||
|  | ||||
|                 StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ ); | ||||
|                 UI.webtoken.access_token_ = NewToken; | ||||
|                 UI.webtoken.refresh_token_ = NewRefreshToken; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|  | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired ) | ||||
|     { | ||||
|         // std::lock_guard	Guard(Mutex_); | ||||
|         std::string CallToken; | ||||
|         Expired = false; | ||||
|  | ||||
| 		try { | ||||
| 		    Poco::Net::OAuth20Credentials Auth(Request); | ||||
| 		    if (Auth.getScheme() == "Bearer") { | ||||
| 		        CallToken = Auth.getBearerToken(); | ||||
| 		    } | ||||
|  | ||||
|             if(CallToken.empty()) { | ||||
|                 poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
| @@ -83,34 +166,40 @@ namespace OpenWifi { | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||
|                 if(RevocationDate!=0) | ||||
|                 if(RevocationDate!=0) { | ||||
|                     poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
|                     return false; | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); | ||||
|                 } | ||||
|                 auto now=OpenWifi::Now(); | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||
|                 if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) { | ||||
|                     UInfo.webtoken = WT; | ||||
|                     SessionToken = CallToken; | ||||
|                     poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken)); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
| 		} catch(const Poco::Exception &E) { | ||||
| 		    Logger().log(E); | ||||
| 		} | ||||
|         poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
| 		return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||
|     bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard	Guard(Mutex_); | ||||
|         // std::lock_guard	Guard(Mutex_); | ||||
|  | ||||
|         std::string CallToken; | ||||
|         Expired = false; | ||||
|         try { | ||||
|             std::string CallToken; | ||||
|             Poco::Net::OAuth20Credentials Auth(Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 CallToken = Auth.getBearerToken(); | ||||
|             } | ||||
|  | ||||
|             if(CallToken.empty()) { | ||||
|                 poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
| @@ -118,19 +207,23 @@ namespace OpenWifi { | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||
|                 if(RevocationDate!=0) | ||||
|                 if(RevocationDate!=0) { | ||||
|                     poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
|                     return false; | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); | ||||
|                 } | ||||
|                 auto now=OpenWifi::Now(); | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||
|                 if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) { | ||||
|                     UInfo.webtoken = WT; | ||||
|                     SessionToken = CallToken; | ||||
|                     poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken)); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } catch(const Poco::Exception &E) { | ||||
|             Logger().log(E); | ||||
|         } | ||||
|         poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken)); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| @@ -180,7 +273,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AuthService::Logout(const std::string &Token, bool EraseFromCache) { | ||||
|     void AuthService::Logout(const std::string &Token,[[maybe_unused]]  bool EraseFromCache) { | ||||
| 		std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
|         try { | ||||
| @@ -192,7 +285,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AuthService::SubLogout(const std::string &Token, bool EraseFromCache) { | ||||
|     void AuthService::SubLogout(const std::string &Token, [[maybe_unused]] bool EraseFromCache) { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
|         try { | ||||
| @@ -204,8 +297,8 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { | ||||
|         std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand())); | ||||
|     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, [[maybe_unused]] ACCESS_TYPE Type) { | ||||
|         std::string Identity(UserName + ":" + fmt::format("{}",OpenWifi::Now()) + ":" + std::to_string(rand())); | ||||
|         HMAC_.update(Identity); | ||||
|         return Poco::DigestEngine::digestToHex(HMAC_.digest()); | ||||
|     } | ||||
| @@ -225,7 +318,7 @@ namespace OpenWifi { | ||||
| 		T.payload().set("identity", Identity); | ||||
| 		T.setIssuedAt(Poco::Timestamp()); | ||||
| 		T.setExpiration(Poco::Timestamp() + (long long)TokenAging_); | ||||
| 		std::string JWT = Signer_.sign(T,Poco::JWT::Signer::ALGO_RS256); | ||||
| 		std::string JWT = MicroService::instance().Sign(T,Poco::JWT::Signer::ALGO_RS256); | ||||
|  | ||||
| 		return JWT; | ||||
|     } | ||||
| @@ -392,7 +485,7 @@ namespace OpenWifi { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
| @@ -421,24 +514,23 @@ namespace OpenWifi { | ||||
|                     UInfo.webtoken.errorCode = 1; | ||||
|                     return PASSWORD_ALREADY_USED; | ||||
|                 } | ||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); | ||||
|                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.changePassword = false; | ||||
|                 UInfo.userinfo.modified = std::time(nullptr); | ||||
|                 UInfo.userinfo.modified = OpenWifi::Now(); | ||||
|                 StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo); | ||||
|             } | ||||
|  | ||||
|             //  so we have a good password, password up date has taken place if need be, now generate the token. | ||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||
|             UInfo.userinfo.lastLogin=OpenWifi::Now(); | ||||
|             StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); | ||||
|             CreateToken(UserName, UInfo ); | ||||
|  | ||||
|             return SUCCESS; | ||||
|         } | ||||
|  | ||||
|         return INVALID_CREDENTIALS; | ||||
|     } | ||||
|  | ||||
|     UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||
|     UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
| @@ -467,14 +559,14 @@ namespace OpenWifi { | ||||
|                     UInfo.webtoken.errorCode = 1; | ||||
|                     return PASSWORD_ALREADY_USED; | ||||
|                 } | ||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); | ||||
|                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.changePassword = false; | ||||
|                 UInfo.userinfo.modified = std::time(nullptr); | ||||
|                 UInfo.userinfo.modified = OpenWifi::Now(); | ||||
|                 StorageService()->SubDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo); | ||||
|             } | ||||
|  | ||||
|             //  so we have a good password, password up date has taken place if need be, now generate the token. | ||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||
|             //  so we have a good password, password update has taken place if need be, now generate the token. | ||||
|             UInfo.userinfo.lastLogin=OpenWifi::Now(); | ||||
|             StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); | ||||
|             CreateSubToken(UserName, UInfo ); | ||||
|  | ||||
| @@ -484,29 +576,62 @@ namespace OpenWifi { | ||||
|         return INVALID_CREDENTIALS; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||
|     bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) { | ||||
|         auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp,":"); | ||||
|         if(UInfo.userinfo.signingUp.empty() || OperatorParts.count()!=2) { | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs); | ||||
|         } else { | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) { | ||||
|         SecurityObjects::UserInfo   UInfo; | ||||
|  | ||||
|         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { | ||||
|             switch (Reason) { | ||||
|  | ||||
|                 case FORGOT_PASSWORD: { | ||||
|                 case MessagingTemplates::FORGOT_PASSWORD: { | ||||
|                         MessageAttributes Attrs; | ||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                         Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                         Attrs[SUBJECT] = "Password reset link"; | ||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||
|                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs); | ||||
|                     } | ||||
|                     break; | ||||
|  | ||||
|                 case EMAIL_VERIFICATION: { | ||||
|                 case MessagingTemplates::EMAIL_VERIFICATION: { | ||||
|                         MessageAttributes Attrs; | ||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                         Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                         Attrs[SUBJECT] = "EMail Address Verification"; | ||||
|                         Attrs[SUBJECT] = "e-mail Address Verification"; | ||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||
|                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs); | ||||
|                         UInfo.waitingForEmailCheck = true; | ||||
|                     } | ||||
|                     break; | ||||
|  | ||||
|                 case MessagingTemplates::EMAIL_INVITATION: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "e-mail Invitation"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_invitation&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_invitation&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs); | ||||
|                     UInfo.waitingForEmailCheck = true; | ||||
|                     } | ||||
|                     break; | ||||
| @@ -519,29 +644,43 @@ namespace OpenWifi { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||
|     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) { | ||||
|         SecurityObjects::UserInfo   UInfo; | ||||
|  | ||||
|         if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) { | ||||
|             switch (Reason) { | ||||
|  | ||||
|                 case FORGOT_PASSWORD: { | ||||
|                 case MessagingTemplates::SUB_FORGOT_PASSWORD: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "Password reset link"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs); | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|                 case EMAIL_VERIFICATION: { | ||||
|                 case MessagingTemplates::SUB_EMAIL_VERIFICATION: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "EMail Address Verification"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||
|                     Attrs[SUBJECT] = "e-mail Address Verification"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_email_verification&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs); | ||||
|                     UInfo.waitingForEmailCheck = true; | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|                 case MessagingTemplates::SIGNUP_VERIFICATION: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "Signup e-mail Address Verification"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs); | ||||
|                     UInfo.waitingForEmailCheck = true; | ||||
|                 } | ||||
|                 break; | ||||
| @@ -558,13 +697,14 @@ namespace OpenWifi { | ||||
|         SecurityObjects::ActionLink A; | ||||
|  | ||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; | ||||
|         A.userId = UInfo.email; | ||||
|         A.userId = UInfo.id; | ||||
|         A.id = MicroService::CreateUUID(); | ||||
|         A.created = std::time(nullptr); | ||||
|         A.created = OpenWifi::Now(); | ||||
|         A.expires = A.created + 24*60*60; | ||||
|         A.userAction = true; | ||||
|         StorageService()->ActionLinksDB().CreateAction(A); | ||||
|         UInfo.waitingForEmailCheck = true; | ||||
|         UInfo.validated = false; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -572,13 +712,14 @@ namespace OpenWifi { | ||||
|         SecurityObjects::ActionLink A; | ||||
|  | ||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL; | ||||
|         A.userId = UInfo.email; | ||||
|         A.userId = UInfo.id; | ||||
|         A.id = MicroService::CreateUUID(); | ||||
|         A.created = std::time(nullptr); | ||||
|         A.created = OpenWifi::Now(); | ||||
|         A.expires = A.created + 24*60*60; | ||||
|         A.userAction = false; | ||||
|         StorageService()->ActionLinksDB().CreateAction(A); | ||||
|         UInfo.waitingForEmailCheck = true; | ||||
|         UInfo.validated = false; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -593,14 +734,15 @@ namespace OpenWifi { | ||||
|         if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||
|             if(RevocationDate!=0) | ||||
|                 return false; | ||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); | ||||
|             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||
|             if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) { | ||||
|                 WebToken = WT; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|         return IsValidSubToken(Token, WebToken, UserInfo, Expired); | ||||
|         // return IsValidSubToken(Token, WebToken, UserInfo, Expired); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { | ||||
| @@ -613,7 +755,7 @@ namespace OpenWifi { | ||||
|         if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||
|             if(RevocationDate!=0) | ||||
|                 return false; | ||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); | ||||
|             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||
|             if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) { | ||||
|                 WebToken = WT; | ||||
|                 return true; | ||||
|   | ||||
| @@ -11,6 +11,8 @@ | ||||
|  | ||||
| #include <regex> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "Poco/JSON/Object.h" | ||||
| #include "Poco/Net/HTTPServerRequest.h" | ||||
| #include "Poco/Net/HTTPServerResponse.h" | ||||
| @@ -20,8 +22,8 @@ | ||||
| #include "Poco/HMACEngine.h" | ||||
| #include "Poco/ExpireLRUCache.h" | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|  | ||||
| @@ -36,11 +38,6 @@ namespace OpenWifi{ | ||||
|             CUSTOM | ||||
|         }; | ||||
|  | ||||
|         enum EMAIL_REASON { | ||||
|             FORGOT_PASSWORD, | ||||
|             EMAIL_VERIFICATION | ||||
|         }; | ||||
|  | ||||
|         static ACCESS_TYPE IntToAccessType(int C); | ||||
|         static int AccessTypeToInt(ACCESS_TYPE T); | ||||
|  | ||||
| @@ -52,14 +49,14 @@ namespace OpenWifi{ | ||||
|         int Start() override; | ||||
|         void Stop() override; | ||||
|  | ||||
|         [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); | ||||
|         [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired); | ||||
|         [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||
|         void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); | ||||
|         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||
|         void Logout(const std::string &token, bool EraseFromCache=true); | ||||
|  | ||||
|         [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); | ||||
|         [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired); | ||||
|         [[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||
|         void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         [[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); | ||||
| @@ -89,10 +86,12 @@ namespace OpenWifi{ | ||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||
|         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); | ||||
|  | ||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason); | ||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName); | ||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|  | ||||
|         [[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code); | ||||
|  | ||||
|         bool DeleteUserFromCache(const std::string &UserName); | ||||
|         bool DeleteSubUserFromCache(const std::string &UserName); | ||||
|         void RevokeToken(std::string & Token); | ||||
| @@ -112,8 +111,10 @@ namespace OpenWifi{ | ||||
|         inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; } | ||||
|         inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; } | ||||
|  | ||||
|         bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI); | ||||
|         bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI); | ||||
|  | ||||
|     private: | ||||
| 		Poco::JWT::Signer	Signer_; | ||||
| 		Poco::SHA2Engine	SHA2_; | ||||
|  | ||||
| 		std::string         AccessPolicy_; | ||||
| @@ -125,8 +126,9 @@ namespace OpenWifi{ | ||||
|         std::regex          PasswordValidation_; | ||||
|         std::regex          SubPasswordValidation_; | ||||
|  | ||||
|         uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | ||||
|         uint64_t            TokenAging_ = 15 * 24 * 60 * 60; | ||||
|         uint64_t            HowManyOldPassword_=5; | ||||
|         uint64_t            RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ; | ||||
|  | ||||
|         class SHA256Engine : public Poco::Crypto::DigestEngine | ||||
|                 { | ||||
| @@ -154,11 +156,11 @@ namespace OpenWifi{ | ||||
|  | ||||
|     inline auto AuthService() { return AuthService::instance(); } | ||||
|  | ||||
|     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) { | ||||
|     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , std::uint64_t TID, bool & Expired, bool Sub ) { | ||||
|         if(Sub) | ||||
|             return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired ); | ||||
|             return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired ); | ||||
|         else | ||||
|             return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); | ||||
|             return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired ); | ||||
|     } | ||||
|  | ||||
| } // end of namespace | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include <cstdlib> | ||||
| #include <boost/algorithm/string.hpp> | ||||
|  | ||||
| #include "Poco/Util/Application.h" | ||||
| #include "Poco/Util/Option.h" | ||||
| @@ -20,11 +18,7 @@ | ||||
| #include "Daemon.h" | ||||
|  | ||||
| #include <aws/core/Aws.h> | ||||
| #include <aws/s3/model/CreateBucketRequest.h> | ||||
| #include <aws/s3/model/PutObjectRequest.h> | ||||
| #include <aws/s3/model/AccessControlPolicy.h> | ||||
| #include <aws/s3/model/PutBucketAclRequest.h> | ||||
| #include <aws/s3/model/GetBucketAclRequest.h> | ||||
|  | ||||
| #include "StorageService.h" | ||||
| #include "SMTPMailerService.h" | ||||
| @@ -56,13 +50,9 @@ namespace OpenWifi { | ||||
|         return instance_; | ||||
|     } | ||||
|  | ||||
|     void Daemon::initialize() { | ||||
|     void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { | ||||
|         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); | ||||
|     } | ||||
|  | ||||
|     void MicroServicePostInitialization() { | ||||
|         Daemon()->initialize(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) { | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/Daemon.h
									
									
									
									
									
								
							| @@ -10,6 +10,8 @@ | ||||
| #include <vector> | ||||
| #include <set> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "Poco/Util/Application.h" | ||||
| #include "Poco/Util/ServerApplication.h" | ||||
| #include "Poco/Util/Option.h" | ||||
| @@ -20,15 +22,14 @@ | ||||
| #include "Poco/Crypto/CipherFactory.h" | ||||
| #include "Poco/Crypto/Cipher.h" | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; | ||||
|     static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; | ||||
|     static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; | ||||
|     static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); | ||||
|     static const uint64_t vDAEMON_BUS_TIMER = 5000; | ||||
|     [[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); | ||||
|     [[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000; | ||||
|  | ||||
|     class Daemon : public MicroService { | ||||
|     public: | ||||
| @@ -40,7 +41,7 @@ namespace OpenWifi { | ||||
|                         const SubSystemVec & SubSystems) : | ||||
|                 MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; | ||||
|  | ||||
|         void initialize(); | ||||
|         void PostInitialization(Poco::Util::Application &self); | ||||
|         static Daemon *instance(); | ||||
|         inline const std::string & AssetDir() { return AssetDir_; } | ||||
|     private: | ||||
| @@ -49,6 +50,9 @@ namespace OpenWifi { | ||||
|     }; | ||||
|  | ||||
|     inline Daemon * Daemon() { return Daemon::instance(); } | ||||
|     inline void DaemonPostInitialization(Poco::Util::Application &self) { | ||||
|         Daemon()->PostInitialization(self); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #endif //UCENTRALSEC_DAEMON_H | ||||
|   | ||||
| @@ -2,10 +2,11 @@ | ||||
| // Created by stephane bourque on 2021-10-11. | ||||
| // | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "MFAServer.h" | ||||
| #include "SMSSender.h" | ||||
| #include "SMTPMailerService.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "AuthService.h" | ||||
| #include "TotpCache.h" | ||||
|  | ||||
| @@ -28,7 +29,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         std::string Challenge = MakeChallenge(); | ||||
|         std::string uuid = MicroService::CreateUUID(); | ||||
|         uint64_t Created = std::time(nullptr); | ||||
|         uint64_t Created = OpenWifi::Now(); | ||||
|  | ||||
|         ChallengeStart.set("uuid",uuid); | ||||
|         ChallengeStart.set("created", Created); | ||||
| @@ -44,12 +45,7 @@ namespace OpenWifi { | ||||
|             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; | ||||
|             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); | ||||
|         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); | ||||
|             return AuthService()->SendEmailChallengeCode(UInfo,Challenge); | ||||
|         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||
|             return true; | ||||
|         } | ||||
| @@ -65,7 +61,7 @@ namespace OpenWifi { | ||||
|         return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer); | ||||
|     } | ||||
|  | ||||
|     bool MFAServer::CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||
|     bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||
|         std::lock_guard G(Mutex_); | ||||
|  | ||||
|         if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer")) | ||||
| @@ -107,7 +103,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     void MFAServer::CleanCache() { | ||||
|         // it is assumed that you have locked Cache_ at this point. | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||
|             if((Now-i->second.Created)>300) { | ||||
|                 i = Cache_.erase(i); | ||||
|   | ||||
| @@ -2,8 +2,7 @@ | ||||
| // Created by stephane bourque on 2021-10-11. | ||||
| // | ||||
|  | ||||
| #ifndef OWSEC_MFASERVER_H | ||||
| #define OWSEC_MFASERVER_H | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "Poco/JSON/Object.h" | ||||
| @@ -41,15 +40,13 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); | ||||
|         bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         static bool MethodEnabled(const std::string &Method); | ||||
|         bool ResendCode(const std::string &uuid); | ||||
|         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||
|  | ||||
|         static inline std::string MakeChallenge() { | ||||
|             char buf[16]; | ||||
|             std::sprintf(buf,"%06llu",MicroService::instance().Random(1,999999)); | ||||
|             return buf; | ||||
|             return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) ); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
| @@ -65,4 +62,3 @@ namespace OpenWifi { | ||||
|     inline auto MFAServer() { return MFAServer::instance(); } | ||||
| } | ||||
|  | ||||
| #endif //OWSEC_MFASERVER_H | ||||
|   | ||||
							
								
								
									
										8
									
								
								src/MessagingTemplates.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/MessagingTemplates.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-07-25. | ||||
| // | ||||
|  | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| } // OpenWifi | ||||
							
								
								
									
										75
									
								
								src/MessagingTemplates.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/MessagingTemplates.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-07-25. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class MessagingTemplates { | ||||
|     public: | ||||
|         static MessagingTemplates & instance() { | ||||
|             static auto instance = new MessagingTemplates; | ||||
|             return *instance; | ||||
|         } | ||||
|  | ||||
|         enum EMAIL_REASON { | ||||
|             FORGOT_PASSWORD = 0, | ||||
|             EMAIL_VERIFICATION, | ||||
|             SIGNUP_VERIFICATION, | ||||
|             EMAIL_INVITATION, | ||||
|             VERIFICATION_CODE, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_EMAIL_VERIFICATION, | ||||
|             SUB_VERIFICATION_CODE | ||||
|         }; | ||||
|  | ||||
|         static std::string AddOperator(const std::string & filename, const std::string &OperatorName) { | ||||
|             if(OperatorName.empty()) | ||||
|                 return "/" + filename; | ||||
|             return "/" + OperatorName + "/" + filename; | ||||
|         } | ||||
|  | ||||
|         static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") { | ||||
|             switch (r) { | ||||
|                 case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName); | ||||
|                 case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName); | ||||
|                 case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName); | ||||
|                 case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName); | ||||
|                 case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName); | ||||
|                 case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName); | ||||
|                 case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName); | ||||
|                 case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName); | ||||
|                 default: | ||||
|                     return ""; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         static std::string Logo(const std::string &OperatorName = "" ) { | ||||
|             return AddOperator("logo.jpg", OperatorName); | ||||
|         } | ||||
|  | ||||
|         static std::string SubLogo(const std::string &OperatorName = "" ) { | ||||
|             return AddOperator("sub_logo.jpg", OperatorName); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         inline const static std::vector<std::string>  EmailTemplateNames = { | ||||
|                 "password_reset", | ||||
|                 "email_verification", | ||||
|                 "signup_verification", | ||||
|                 "email_invitation", | ||||
|                 "verification_code", | ||||
|                 "sub_password_reset", | ||||
|                 "sub_email_verification", | ||||
|                 "sub_verification_code" | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); } | ||||
|  | ||||
| } // OpenWifi | ||||
|  | ||||
| @@ -23,8 +23,14 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(Action=="password_reset") | ||||
|             return RequestResetPassword(Link); | ||||
|         else if(Action=="sub_password_reset") | ||||
|             return RequestSubResetPassword(Link); | ||||
|         else if(Action=="email_verification") | ||||
|             return DoEmailVerification(Link); | ||||
|         else if(Action=="sub_email_verification") | ||||
|             return DoSubEmailVerification(Link); | ||||
|         else if(Action=="signup_verification") | ||||
|             return DoNewSubVerification(Link); | ||||
|         else | ||||
|             return DoReturnA404(); | ||||
|     } | ||||
| @@ -34,18 +40,32 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(Action=="password_reset") | ||||
|             return CompleteResetPassword(); | ||||
|         else if(Action=="sub_password_reset") | ||||
|             return CompleteResetPassword(); | ||||
|         else if(Action=="signup_completion") | ||||
|             return CompleteSubVerification(); | ||||
|         else if(Action=="email_invitation") | ||||
|             return CompleteEmailInvitation(); | ||||
|         else | ||||
|             return DoReturnA404(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) { | ||||
|         Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId)); | ||||
|         Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId)); | ||||
|         Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; | ||||
|         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||
|         SendHTMLFileBack(FormFile,FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) { | ||||
|         Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId)); | ||||
|         Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification.html"}; | ||||
|         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||
|         SendHTMLFileBack(FormFile,FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::CompleteResetPassword() { | ||||
|         //  form has been posted... | ||||
|         RESTAPI_PartHandler PartHandler; | ||||
| @@ -53,15 +73,15 @@ namespace OpenWifi { | ||||
|         if (!Form.empty()) { | ||||
|  | ||||
|             auto Password1 = Form.get("password1","bla"); | ||||
|             auto Password2 = Form.get("password1","blu"); | ||||
|             auto Password2 = Form.get("password2","blu"); | ||||
|             auto Id = Form.get("id",""); | ||||
|             auto Now = std::time(nullptr); | ||||
|             auto now = OpenWifi::Now(); | ||||
|  | ||||
|             SecurityObjects::ActionLink Link; | ||||
|             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) | ||||
|                 return DoReturnA404(); | ||||
|  | ||||
|             if(Now > Link.expires) { | ||||
|             if(now > Link.expires) { | ||||
|                 StorageService()->ActionLinksDB().CancelAction(Id); | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
| @@ -101,7 +121,7 @@ namespace OpenWifi { | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             UInfo.modified = std::time(nullptr); | ||||
|             UInfo.modified = OpenWifi::Now(); | ||||
|             if(Link.userAction) | ||||
|                 StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||
|             else | ||||
| @@ -118,10 +138,102 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) { | ||||
|         auto Now = std::time(nullptr); | ||||
|     void RESTAPI_action_links::CompleteSubVerification() { | ||||
|         RESTAPI_PartHandler PartHandler; | ||||
|         Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); | ||||
|  | ||||
|         if(Now > Link.expires) { | ||||
|         if (!Form.empty()) { | ||||
|             auto Password1 = Form.get("password1","bla"); | ||||
|             auto Password2 = Form.get("password2","blu"); | ||||
|             auto Id = Form.get("id",""); | ||||
|             auto now = OpenWifi::Now(); | ||||
|  | ||||
|             SecurityObjects::ActionLink Link; | ||||
|             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) { | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
|  | ||||
|             if(now > Link.expires) { | ||||
|                 StorageService()->ActionLinksDB().CancelAction(Id); | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
|  | ||||
|             if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with" | ||||
|                                                                  " accepted password creation restrictions. Please consult our on-line help" | ||||
|                                                                  " to look at the our password policy. If you would like to contact us, please mention" | ||||
|                                                                  " id(" + Id + ")"}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             SecurityObjects::UserInfo   UInfo; | ||||
|             bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo); | ||||
|             if(!Found) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             if(UInfo.blackListed || UInfo.suspended) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo); | ||||
|             if(!GoodPassword) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             UInfo.modified = OpenWifi::Now(); | ||||
|             UInfo.changePassword = false; | ||||
|             UInfo.lastEmailCheck = OpenWifi::Now(); | ||||
|             UInfo.waitingForEmailCheck = false; | ||||
|             UInfo.validated = OpenWifi::Now(); | ||||
|  | ||||
|             StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||
|  | ||||
|             Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"}; | ||||
|             Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                               {"USERNAME", UInfo.email} }; | ||||
|             StorageService()->ActionLinksDB().CompleteAction(Id); | ||||
|  | ||||
|             //  Send the update to the provisioning service | ||||
|             Poco::JSON::Object  Body; | ||||
|             auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|             Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]); | ||||
|             OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup", | ||||
|                                             { | ||||
|                                                 {"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} , | ||||
|                                                 {"operation", "emailVerified"} | ||||
|                                             }, | ||||
|                                             Body,30000); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email)); | ||||
|             Poco::JSON::Object::Ptr Response; | ||||
|             auto Status = ProvRequest.Do(Response); | ||||
|             std::stringstream ooo; | ||||
|             if(Response!= nullptr) | ||||
|                 Response->stringify(ooo); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.", | ||||
|                                              UInfo.email, Status)); | ||||
|             SendHTMLFileBack(FormFile,FormVars); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification. FORM notified.",UInfo.email)); | ||||
|         } else { | ||||
|             DoReturnA404(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) { | ||||
|         auto now = OpenWifi::Now(); | ||||
|  | ||||
|         if(now > Link.expires) { | ||||
|             StorageService()->ActionLinksDB().CancelAction(Link.id); | ||||
|             return DoReturnA404(); | ||||
|         } | ||||
| @@ -135,12 +247,13 @@ namespace OpenWifi { | ||||
|             return SendHTMLFileBack(FormFile, FormVars); | ||||
|         } | ||||
|  | ||||
|         Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email)); | ||||
|         Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(), | ||||
|                                         UInfo.email)); | ||||
|         UInfo.waitingForEmailCheck = false; | ||||
|         UInfo.validated = true; | ||||
|         UInfo.lastEmailCheck = std::time(nullptr); | ||||
|         UInfo.validationDate = std::time(nullptr); | ||||
|         UInfo.modified  = std::time(nullptr); | ||||
|         UInfo.lastEmailCheck = OpenWifi::Now(); | ||||
|         UInfo.validationDate = OpenWifi::Now(); | ||||
|         UInfo.modified  = OpenWifi::Now(); | ||||
|         if(Link.userAction) | ||||
|             StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||
|         else | ||||
| @@ -159,4 +272,16 @@ namespace OpenWifi { | ||||
|         SendHTMLFileBack(FormFile, FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::CompleteEmailInvitation() { | ||||
|         /// TODO: | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -20,11 +20,16 @@ namespace OpenWifi { | ||||
|                                         Internal, | ||||
|                                         false, | ||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; }; | ||||
|         void RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||
|         void RequestSubResetPassword(SecurityObjects::ActionLink &Link); | ||||
|         void CompleteResetPassword(); | ||||
|         void CompleteSubVerification(); | ||||
|         void DoEmailVerification(SecurityObjects::ActionLink &Link); | ||||
|         void DoSubEmailVerification(SecurityObjects::ActionLink &Link); | ||||
|         void DoReturnA404(); | ||||
|         void DoNewSubVerification(SecurityObjects::ActionLink &Link); | ||||
|         void CompleteEmailInvitation(); | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  | ||||
| #include "RESTAPI_asset_server.h" | ||||
| #include "Poco/File.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "Daemon.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal, false) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" , | ||||
|         static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" , | ||||
|                                                                                          "/favicon.ico"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
| #include "RESTAPI_avatar_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "Poco/Net/HTMLForm.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| @@ -38,10 +37,11 @@ namespace OpenWifi { | ||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); | ||||
|             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); | ||||
|             Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType())); | ||||
|             StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, | ||||
|                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); | ||||
|             StorageService()->UserDB().SetAvatar(Id,"1"); | ||||
|             Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email)); | ||||
|         } else { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||
| @@ -60,6 +60,7 @@ namespace OpenWifi { | ||||
|         if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size())); | ||||
|         return SendFileContent(AvatarContent, Type, Name); | ||||
|     } | ||||
|  | ||||
| @@ -67,13 +68,14 @@ namespace OpenWifi { | ||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
|  | ||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
|         Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email)); | ||||
|         StorageService()->UserDB().SetAvatar(Id,""); | ||||
|         OK(); | ||||
|     } | ||||
|   | ||||
| @@ -26,6 +26,8 @@ namespace OpenWifi { | ||||
|         std::string     Id_; | ||||
|         Poco::Logger    &Logger_; | ||||
|         std::stringstream &OutputStream_; | ||||
|  | ||||
|         inline Poco::Logger & Logger() { return Logger_; }; | ||||
|     }; | ||||
|  | ||||
|     class RESTAPI_avatar_handler : public RESTAPIHandler { | ||||
| @@ -40,7 +42,7 @@ namespace OpenWifi { | ||||
|                                          Server, | ||||
|                                          TransactionId, | ||||
|                                          Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/avatar/{id}"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; }; | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     inline void Sanitize(const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) { | ||||
|     inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) { | ||||
|         U.currentPassword.clear(); | ||||
|         U.lastPasswords.clear(); | ||||
|         U.oauthType.clear(); | ||||
|   | ||||
| @@ -9,12 +9,12 @@ | ||||
| #include "Poco/JSON/Parser.h" | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     void RESTAPI_email_handler::DoPost() { | ||||
|         auto Obj = ParseStream(); | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         if (Obj->has("subject") && | ||||
|             Obj->has("from") && | ||||
|             Obj->has("text") && | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                   Server, | ||||
|                                                   TransactionId, | ||||
|                                                   Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/email"};} | ||||
|         void DoGet() final {}; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI_oauth2_handler.h" | ||||
| #include "MFAServer.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| @@ -21,13 +21,13 @@ namespace OpenWifi { | ||||
|     void RESTAPI_oauth2_handler::DoGet() { | ||||
|         bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|             if (Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||
|         } | ||||
|         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||
|         if(GetMe) { | ||||
|             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||
|         if (GetBoolParameter(RESTAPI::Protocol::ME)) { | ||||
|             Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(), | ||||
|                                             UserInfo_.userinfo.email)); | ||||
|             Poco::JSON::Object Me; | ||||
|             SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo; | ||||
|             Sanitize(UserInfo_, ReturnedUser); | ||||
| @@ -38,33 +38,52 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_oauth2_handler::DoDelete() { | ||||
| 	    bool Expired = false, Contacted=false; | ||||
| 	    if (!IsAuthorized(Expired, Contacted)) { | ||||
| 	        if(Expired) | ||||
| 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
| 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, ""); | ||||
|         std::string SessionToken; | ||||
|         try { | ||||
|             Poco::Net::OAuth20Credentials Auth(*Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 SessionToken = Auth.getBearerToken(); | ||||
|             } | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|         if (Token.empty() || (Token != SessionToken)) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|  | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||
|         if (Token == SessionToken_) { | ||||
|         AuthService()->Logout(Token); | ||||
|         return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); | ||||
|     } | ||||
|  | ||||
|         Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||
|         NotFound(); | ||||
| 	void RESTAPI_oauth2_handler::DoPost() { | ||||
|  | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         if(Obj == nullptr) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
| 	void RESTAPI_oauth2_handler::DoPost() { | ||||
|         auto Obj = ParseStream(); | ||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); | ||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); | ||||
|         auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj); | ||||
|         auto refreshToken = GetS("refreshToken", Obj); | ||||
|         auto grant_type = GetParameter("grant_type"); | ||||
|  | ||||
|         Poco::toLowerInPlace(userId); | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) { | ||||
|             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); | ||||
|         if(!refreshToken.empty() && grant_type == "refresh_token") { | ||||
|             SecurityObjects::UserInfoAndPolicy UInfo; | ||||
|             if(AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) { | ||||
|                 Poco::JSON::Object  Answer; | ||||
|                 UInfo.webtoken.to_json(Answer); | ||||
|                 return ReturnObject(Answer); | ||||
|             } else { | ||||
|                 return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) { | ||||
|             Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString())); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression()); | ||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy()); | ||||
| @@ -72,17 +91,17 @@ namespace OpenWifi { | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||
|             SecurityObjects::UserInfo UInfo1; | ||||
|             auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1); | ||||
|             if(UserExists) { | ||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|                 Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|                 SecurityObjects::ActionLink NewLink; | ||||
|  | ||||
|                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; | ||||
|                 NewLink.id = MicroService::CreateUUID(); | ||||
|                 NewLink.userId = UInfo1.id; | ||||
|                 NewLink.created = std::time(nullptr); | ||||
|                 NewLink.created = OpenWifi::Now(); | ||||
|                 NewLink.expires = NewLink.created + (24*60*60); | ||||
|                 NewLink.userAction = true; | ||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
| @@ -101,18 +120,18 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { | ||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) { | ||||
|             Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|             if(Obj->has("uuid")) { | ||||
|                 auto uuid = Obj->get("uuid").toString(); | ||||
|                 if(MFAServer()->ResendCode(uuid)) | ||||
|                     return OK(); | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); | ||||
|             return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|             Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|             if(Obj->has("uuid")) { | ||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||
|                 if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) { | ||||
| @@ -121,7 +140,7 @@ namespace OpenWifi { | ||||
|                     return ReturnObject(ReturnObj); | ||||
|                 } | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); | ||||
|             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfoAndPolicy UInfo; | ||||
| @@ -141,17 +160,17 @@ namespace OpenWifi { | ||||
|  | ||||
|             switch(Code) { | ||||
|                 case INVALID_CREDENTIALS: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|                 case PASSWORD_INVALID: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||
|                 case PASSWORD_ALREADY_USED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||
|                 case USERNAME_PENDING_VERIFICATION: | ||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||
|                 case PASSWORD_CHANGE_REQUIRED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||
|                 default: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ namespace OpenWifi { | ||||
| 													  Server, | ||||
|                                                       TransactionId, | ||||
| 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||
| 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoDelete() final; | ||||
|   | ||||
| @@ -19,13 +19,13 @@ namespace OpenWifi { | ||||
|  | ||||
|         SecurityObjects::Preferences    P; | ||||
|  | ||||
|         auto RawObject = ParseStream(); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!P.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         P.id = UserInfo_.userinfo.id; | ||||
|         P.modified = std::time(nullptr); | ||||
|         P.modified = OpenWifi::Now(); | ||||
|         StorageService()->PreferencesDB().SetPreferences(P); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal) {} | ||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/preferences"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPut() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -24,15 +24,17 @@ | ||||
| #include "RESTAPI/RESTAPI_submfa_handler.h" | ||||
| #include "RESTAPI/RESTAPI_totp_handler.h" | ||||
| #include "RESTAPI/RESTAPI_subtotp_handler.h" | ||||
| #include "RESTAPI/RESTAPI_signup_handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings, | ||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, | ||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S, | ||||
|                                                             uint64_t TransactionId) { | ||||
|         return RESTAPI_Router< | ||||
|             RESTAPI_oauth2_handler, | ||||
|             RESTAPI_users_handler, | ||||
|             RESTAPI_user_handler, | ||||
|             RESTAPI_users_handler, | ||||
|             RESTAPI_system_command, | ||||
|             RESTAPI_asset_server, | ||||
|             RESTAPI_system_endpoints_handler, | ||||
| @@ -48,26 +50,39 @@ namespace OpenWifi { | ||||
|             RESTAPI_subusers_handler, | ||||
|             RESTAPI_submfa_handler, | ||||
|             RESTAPI_totp_handler, | ||||
|             RESTAPI_subtotp_handler | ||||
|             RESTAPI_subtotp_handler, | ||||
|             RESTAPI_signup_handler, | ||||
|             RESTAPI_validate_sub_token_handler, | ||||
|             RESTAPI_validate_token_handler | ||||
|         >(Path, Bindings, L, S,TransactionId); | ||||
|     } | ||||
|  | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const char *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) { | ||||
|  | ||||
|         return RESTAPI_Router_I< | ||||
|             RESTAPI_users_handler, | ||||
|             RESTAPI_oauth2_handler, | ||||
|             RESTAPI_user_handler, | ||||
|             RESTAPI_subuser_handler, | ||||
|             RESTAPI_subusers_handler, | ||||
|             RESTAPI_users_handler, | ||||
|             RESTAPI_system_command, | ||||
|             RESTAPI_asset_server, | ||||
|             RESTAPI_system_endpoints_handler, | ||||
|             RESTAPI_action_links, | ||||
|             RESTAPI_validate_token_handler, | ||||
|             RESTAPI_validate_sub_token_handler, | ||||
|             RESTAPI_avatar_handler, | ||||
|             RESTAPI_subavatar_handler, | ||||
|             RESTAPI_email_handler, | ||||
|             RESTAPI_sms_handler, | ||||
|             RESTAPI_preferences, | ||||
|             RESTAPI_subpreferences, | ||||
|             RESTAPI_suboauth2_handler, | ||||
|             RESTAPI_submfa_handler | ||||
|             RESTAPI_subuser_handler, | ||||
|             RESTAPI_subusers_handler, | ||||
|             RESTAPI_submfa_handler, | ||||
|             RESTAPI_totp_handler, | ||||
|             RESTAPI_subtotp_handler, | ||||
|             RESTAPI_validate_sub_token_handler, | ||||
|             RESTAPI_validate_token_handler, | ||||
|             RESTAPI_signup_handler | ||||
|         >(Path, Bindings, L, S, TransactionId); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										74
									
								
								src/RESTAPI/RESTAPI_signup_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/RESTAPI/RESTAPI_signup_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-02-20. | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_signup_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| #define __DBG__ std::cout << __LINE__ << std::endl; | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_signup_handler::DoPost() { | ||||
|         auto UserName = GetParameter("email"); | ||||
|         auto signupUUID = GetParameter("signupUUID"); | ||||
|         auto owner = GetParameter("owner"); | ||||
|         auto operatorName = GetParameter("operatorName"); | ||||
|         if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) { | ||||
|             Logger().error("Signup requires: email, signupUUID, operatorName, and owner."); | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|  | ||||
|         if(!Utils::ValidEMailAddress(UserName)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||
|         } | ||||
|  | ||||
|         // Do we already exist? Can only signup once... | ||||
|         SecurityObjects::UserInfo   Existing; | ||||
|         if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) { | ||||
|             if(Existing.signingUp.empty()) { | ||||
|                 return BadRequest(RESTAPI::Errors::SignupAlreadySigned); | ||||
|             } | ||||
|  | ||||
|             if(Existing.waitingForEmailCheck) { | ||||
|                 return BadRequest(RESTAPI::Errors::SignupEmailCheck); | ||||
|             } | ||||
|  | ||||
|             return BadRequest(RESTAPI::Errors::SignupWaitingForDevice); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewSub; | ||||
|         NewSub.signingUp = operatorName + ":" + signupUUID; | ||||
|         NewSub.waitingForEmailCheck = true; | ||||
|         NewSub.name = UserName; | ||||
|         NewSub.modified = OpenWifi::Now(); | ||||
|         NewSub.creationDate = OpenWifi::Now(); | ||||
|         NewSub.id = MicroService::instance().CreateUUID(); | ||||
|         NewSub.email = UserName; | ||||
|         NewSub.userRole = SecurityObjects::SUBSCRIBER; | ||||
|         NewSub.changePassword = true; | ||||
|         NewSub.owner = owner; | ||||
|  | ||||
|         StorageService()->SubDB().CreateRecord(NewSub); | ||||
|  | ||||
|         Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName)); | ||||
|         SecurityObjects::ActionLink NewLink; | ||||
|  | ||||
|         NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP; | ||||
|         NewLink.id = MicroService::CreateUUID(); | ||||
|         NewLink.userId = NewSub.id; | ||||
|         NewLink.created = OpenWifi::Now(); | ||||
|         NewLink.expires = NewLink.created + (1*60*60);  // 1 hour | ||||
|         NewLink.userAction = false; | ||||
|         StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|         NewSub.to_json(Answer); | ||||
|         return ReturnObject(Answer); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_signup_handler::DoPut() { | ||||
|         // TODO | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										39
									
								
								src/RESTAPI/RESTAPI_signup_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/RESTAPI/RESTAPI_signup_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-02-20. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_signup_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|                 : RESTAPIHandler(bindings, L, | ||||
|                                  std::vector<std::string>{ | ||||
|                                          Poco::Net::HTTPRequest::HTTP_POST, | ||||
|                                          Poco::Net::HTTPRequest::HTTP_OPTIONS, | ||||
|                                          Poco::Net::HTTPRequest::HTTP_PUT}, | ||||
|                                  Server, | ||||
|                                  TransactionId, | ||||
|                                  Internal, false, true ){} | ||||
|  | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/signup"}; }; | ||||
|  | ||||
| /*        inline bool RoleIsAuthorized(std::string & Reason) { | ||||
|             if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) { | ||||
|                 Reason = "User must be a subscriber"; | ||||
|                 return false; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| */ | ||||
|         void DoGet() final {}; | ||||
|         void DoPost() final; | ||||
|         void DoPut() final ; | ||||
|         void DoDelete() final {}; | ||||
|     private: | ||||
|  | ||||
|     }; | ||||
| } | ||||
| @@ -4,13 +4,17 @@ | ||||
|  | ||||
| #include "RESTAPI_sms_handler.h" | ||||
| #include "SMSSender.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void OpenWifi::RESTAPI_sms_handler::DoPost() { | ||||
|         auto Obj = ParseStream(); | ||||
|         const auto &Obj = ParsedBody_; | ||||
|  | ||||
|         if(!SMSSender()->Enabled()) { | ||||
|             return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|         } | ||||
|  | ||||
|         std::string Arg; | ||||
|         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { | ||||
| @@ -36,7 +40,7 @@ namespace OpenWifi { | ||||
|         if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && | ||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER && | ||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights,ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (Obj->has("to") && | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                   Server, | ||||
|                                                   TransactionId, | ||||
|                                                   Internal) {} | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/sms"};} | ||||
|         void DoGet() final {}; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
| #include "RESTAPI_subavatar_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "Poco/Net/HTMLForm.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| @@ -38,10 +37,11 @@ namespace OpenWifi { | ||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); | ||||
|             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); | ||||
|             Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType())); | ||||
|             StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email, | ||||
|                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); | ||||
|             StorageService()->SubDB().SetAvatar(Id,"1"); | ||||
|             Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email)); | ||||
|         } else { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||
| @@ -60,6 +60,7 @@ namespace OpenWifi { | ||||
|         if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Retrieving avatar for {}",UserInfo_.userinfo.email)); | ||||
|         return SendFileContent(AvatarContent, Type, Name); | ||||
|     } | ||||
|  | ||||
| @@ -67,12 +68,13 @@ namespace OpenWifi { | ||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
|  | ||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email)); | ||||
|         StorageService()->SubDB().SetAvatar(Id,""); | ||||
|         OK(); | ||||
|     } | ||||
|   | ||||
| @@ -26,6 +26,8 @@ namespace OpenWifi { | ||||
|         std::string     Id_; | ||||
|         Poco::Logger    &Logger_; | ||||
|         std::stringstream &OutputStream_; | ||||
|  | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
|  | ||||
|     class RESTAPI_subavatar_handler : public RESTAPIHandler { | ||||
| @@ -40,7 +42,7 @@ namespace OpenWifi { | ||||
|                                          Server, | ||||
|                                          TransactionId, | ||||
|                                          Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subavatar/{id}"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; }; | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -11,7 +11,6 @@ namespace OpenWifi { | ||||
|     void RESTAPI_submfa_handler::DoGet() { | ||||
|         SecurityObjects::UserInfo   User; | ||||
|  | ||||
|         // std::cout << "submfa get " << UserInfo_.userinfo.Id << "   user:" << UserInfo_.userinfo.email << std::endl; | ||||
|         if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) { | ||||
|             Poco::JSON::Object              Answer; | ||||
|             SecurityObjects::SubMfaConfig   MFC; | ||||
| @@ -37,7 +36,7 @@ namespace OpenWifi { | ||||
|     void RESTAPI_submfa_handler::DoPut() { | ||||
|  | ||||
|         try { | ||||
|             auto Body = ParseStream(); | ||||
|             const auto & Body = ParsedBody_; | ||||
|  | ||||
|             SecurityObjects::SubMfaConfig MFC; | ||||
|  | ||||
| @@ -74,21 +73,30 @@ namespace OpenWifi { | ||||
|             } else if (MFC.type == "sms") { | ||||
|                 if (GetBoolParameter("startValidation", false)) { | ||||
|                     if (MFC.sms.empty()) { | ||||
|                         return BadRequest("Missing phone number"); | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); | ||||
|                     } | ||||
|  | ||||
|                     if(!SMSSender()->Enabled()) { | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                     } | ||||
|  | ||||
|                     if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) { | ||||
|                         return OK(); | ||||
|                     } else { | ||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); | ||||
|                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||
|                     } | ||||
|                 } else if (GetBoolParameter("completeValidation", false)) { | ||||
|  | ||||
|                     if(!SMSSender()->Enabled()) { | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                     } | ||||
|  | ||||
|                     auto ChallengeCode = GetParameter("challengeCode", ""); | ||||
|                     if (ChallengeCode.empty()) { | ||||
|                         return BadRequest("Missing 'challengeCode'"); | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingChallenge); | ||||
|                     } | ||||
|                     if (MFC.sms.empty()) { | ||||
|                         return BadRequest("Missing phone number"); | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); | ||||
|                     } | ||||
|                     if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) { | ||||
|                         SecurityObjects::UserInfo User; | ||||
| @@ -116,7 +124,7 @@ namespace OpenWifi { | ||||
|                         return ReturnObject(Answer); | ||||
|  | ||||
|                     } else { | ||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); | ||||
|                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                                   TransactionId, | ||||
|                                                   Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10}, | ||||
|                                                   true) {} | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/submfa"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include "RESTAPI_suboauth2_handler.h" | ||||
| #include "AuthService.h" | ||||
| #include "MFAServer.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -16,12 +15,12 @@ namespace OpenWifi { | ||||
|         bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted, true)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||
|         } | ||||
|         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||
|         if(GetMe) { | ||||
|             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), | ||||
|             Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(), | ||||
|                                              UserInfo_.userinfo.email)); | ||||
|             Poco::JSON::Object Me; | ||||
|             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; | ||||
| @@ -33,33 +32,46 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_suboauth2_handler::DoDelete() { | ||||
|         bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted, true)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, ""); | ||||
|         std::string SessionToken; | ||||
|         try { | ||||
|             Poco::Net::OAuth20Credentials Auth(*Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 SessionToken = Auth.getBearerToken(); | ||||
|             } | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|         if (Token.empty() || (Token != SessionToken)) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|  | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||
|         if (Token == SessionToken_) { | ||||
|         AuthService()->SubLogout(Token); | ||||
|         return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); | ||||
|     } | ||||
|  | ||||
|         Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||
|         NotFound(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_suboauth2_handler::DoPost() { | ||||
|         auto Obj = ParseStream(); | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); | ||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); | ||||
|         auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj); | ||||
|         auto refreshToken = GetS("refreshToken", Obj); | ||||
|         auto grant_type = GetParameter("grant_type"); | ||||
|  | ||||
|         Poco::toLowerInPlace(userId); | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) { | ||||
|             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); | ||||
|         if(!refreshToken.empty() && grant_type == "refresh_token") { | ||||
|             SecurityObjects::UserInfoAndPolicy UInfo; | ||||
|             if(AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) { | ||||
|                 Poco::JSON::Object  Answer; | ||||
|                 UInfo.webtoken.to_json(Answer); | ||||
|                 return ReturnObject(Answer); | ||||
|             } else { | ||||
|                 return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) { | ||||
|             Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString())); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression()); | ||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy()); | ||||
| @@ -67,17 +79,17 @@ namespace OpenWifi { | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||
|             SecurityObjects::UserInfo UInfo1; | ||||
|             auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1); | ||||
|             if(UserExists) { | ||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|                 Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|                 SecurityObjects::ActionLink NewLink; | ||||
|  | ||||
|                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD; | ||||
|                 NewLink.id = MicroService::CreateUUID(); | ||||
|                 NewLink.userId = UInfo1.id; | ||||
|                 NewLink.created = std::time(nullptr); | ||||
|                 NewLink.created = OpenWifi::Now(); | ||||
|                 NewLink.expires = NewLink.created + (24*60*60); | ||||
|                 NewLink.userAction = false; | ||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
| @@ -96,18 +108,18 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { | ||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) { | ||||
|             Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|             if(Obj->has("uuid")) { | ||||
|                 auto uuid = Obj->get("uuid").toString(); | ||||
|                 if(MFAServer()->ResendCode(uuid)) | ||||
|                     return OK(); | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); | ||||
|             return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) { | ||||
|             Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|             if(Obj->has("uuid") && Obj->has("answer")) { | ||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||
|                 if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) { | ||||
| @@ -116,7 +128,7 @@ namespace OpenWifi { | ||||
|                     return ReturnObject(ReturnObj); | ||||
|                 } | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); | ||||
|             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfoAndPolicy UInfo; | ||||
| @@ -135,17 +147,17 @@ namespace OpenWifi { | ||||
|         } else { | ||||
|             switch(Code) { | ||||
|                 case INVALID_CREDENTIALS: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|                 case PASSWORD_INVALID: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||
|                 case PASSWORD_ALREADY_USED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||
|                 case USERNAME_PENDING_VERIFICATION: | ||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||
|                 case PASSWORD_CHANGE_REQUIRED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||
|                 default: | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                                   TransactionId, | ||||
|                                                   Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10}, | ||||
|                                                   false) {} | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -19,13 +19,13 @@ namespace OpenWifi { | ||||
|  | ||||
|         SecurityObjects::Preferences    P; | ||||
|  | ||||
|         auto RawObject = ParseStream(); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!P.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         P.id = UserInfo_.userinfo.id; | ||||
|         P.modified = std::time(nullptr); | ||||
|         P.modified = OpenWifi::Now(); | ||||
|         StorageService()->SubPreferencesDB().SetPreferences(P); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal) {} | ||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subpreferences"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPut() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -24,15 +24,14 @@ namespace OpenWifi { | ||||
|         auto nextIndex = GetParameter("index",0); | ||||
|         bool moreCodes=false; | ||||
|  | ||||
|         uint64_t ErrorCode = 0; | ||||
|         std::string ErrorText; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, ErrorCode, ErrorText )) { | ||||
|         RESTAPI::Errors::msg    Error; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) { | ||||
|             Poco::JSON::Object Answer; | ||||
|             Answer.set("nextIndex", nextIndex); | ||||
|             Answer.set("moreCodes", moreCodes); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         return BadRequest(ErrorCode, ErrorText); | ||||
|         return BadRequest(Error); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                  Server, | ||||
|                                  TransactionId, | ||||
|                                  Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subtotp"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -4,8 +4,9 @@ | ||||
|  | ||||
| #include "RESTAPI_subuser_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "SMSSender.h" | ||||
| #include "SMTPMailerService.h" | ||||
| #include "ACLProcessor.h" | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -52,8 +53,8 @@ namespace OpenWifi { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||
| @@ -64,7 +65,7 @@ namespace OpenWifi { | ||||
|         StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email); | ||||
|         StorageService()->SubPreferencesDB().DeleteRecord("id", Id); | ||||
|         StorageService()->SubAvatarDB().DeleteRecord("id", Id); | ||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||
|         Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email)); | ||||
|         OK(); | ||||
|     } | ||||
|  | ||||
| @@ -75,13 +76,23 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         RESTAPI_utils::from_request(NewUser,*Request); | ||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) { | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|         } | ||||
|  | ||||
|         Poco::toLowerInPlace(NewUser.email); | ||||
|         SecurityObjects::UserInfo   Existing; | ||||
|         if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) { | ||||
|             return BadRequest(RESTAPI::Errors::UserAlreadyExists); | ||||
|         } | ||||
|  | ||||
|         if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::toLowerInPlace(NewUser.email); | ||||
| @@ -104,19 +115,19 @@ namespace OpenWifi { | ||||
|         NewUser.userTypeProprietaryInfo.mobiles.clear(); | ||||
|         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|  | ||||
|         if(!StorageService()->SubDB().CreateUser(NewUser.email, NewUser)) { | ||||
|             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); | ||||
|         if(!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) { | ||||
|             Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email)); | ||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||
|         } | ||||
|  | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|             if(AuthService::VerifySubEmail(NewUser)) | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email)); | ||||
|             StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) { | ||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||
|             Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email)); | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
| @@ -124,7 +135,7 @@ namespace OpenWifi { | ||||
|         Sanitize(UserInfo_, NewUser); | ||||
|         NewUser.to_json(UserInfoObject); | ||||
|         ReturnObject(UserInfoObject); | ||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|         Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_subuser_handler::DoPut() { | ||||
| @@ -138,12 +149,52 @@ namespace OpenWifi { | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||
|         if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("resetMFA")) { | ||||
|             if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) || | ||||
|                 (UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) || | ||||
|                 (UserInfo_.userinfo.id == Id)) { | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = false; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                 Existing.modified = OpenWifi::Now(); | ||||
|                 Existing.notes.push_back( SecurityObjects::NoteInfo{ | ||||
|                         .created=OpenWifi::Now(), | ||||
|                         .createdBy=UserInfo_.userinfo.email, | ||||
|                         .note="MFA Reset by " + UserInfo_.userinfo.email}); | ||||
|                 StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing); | ||||
|                 SecurityObjects::UserInfo   NewUserInfo; | ||||
|                 StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||
|                 Poco::JSON::Object  ModifiedObject; | ||||
|                 Sanitize(UserInfo_, NewUserInfo); | ||||
|                 NewUserInfo.to_json(ModifiedObject); | ||||
|                 return ReturnObject(ModifiedObject); | ||||
|             } else { | ||||
|                 return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("forgotPassword")) { | ||||
|             Existing.changePassword = true; | ||||
|             Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email)); | ||||
|  | ||||
|             SecurityObjects::ActionLink NewLink; | ||||
|             NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD; | ||||
|             NewLink.id = MicroService::CreateUUID(); | ||||
|             NewLink.userId = Existing.id; | ||||
|             NewLink.created = OpenWifi::Now(); | ||||
|             NewLink.expires = NewLink.created + (24*60*60); | ||||
|             NewLink.userAction = false; | ||||
|             StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
|  | ||||
|             return OK(); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         auto RawObject = ParseStream(); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| @@ -169,10 +220,10 @@ namespace OpenWifi { | ||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||
|             if(NewRole!=Existing.userRole) { | ||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                 } | ||||
|                 if(Id==UserInfo_.userinfo.id) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                 } | ||||
|                 Existing.userRole = NewRole; | ||||
|             } | ||||
| @@ -182,7 +233,7 @@ namespace OpenWifi { | ||||
|             SecurityObjects::NoteInfoVec NIV; | ||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||
|             for(auto const &i:NIV) { | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 Existing.notes.push_back(ii); | ||||
|             } | ||||
|         } | ||||
| @@ -197,7 +248,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|             if(AuthService::VerifySubEmail(Existing)) | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email)); | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email)); | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("userTypeProprietaryInfo")) { | ||||
| @@ -206,23 +257,32 @@ namespace OpenWifi { | ||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||
|                 } | ||||
|  | ||||
|                 bool ChangingMFA = | ||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||
|  | ||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||
|                     if (PInfo->isArray("mobiles")) { | ||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||
|                     !SMSSender()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                 } | ||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || | ||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, | ||||
|                                                     UserInfo_.userinfo.email)) { | ||||
|  | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL && | ||||
|                     !SMTPMailerService()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::EMailMFANotEnabled); | ||||
|                 } | ||||
|  | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|  | ||||
|                 if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     if(NewUser.userTypeProprietaryInfo.mobiles.empty()) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles[0].verified = true; | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                     std::string Secret; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||
| @@ -232,13 +292,10 @@ namespace OpenWifi { | ||||
|                     } else { | ||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||
|                     } | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     // nothing to do for email. | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|             } else { | ||||
|                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {} | ||||
|                           static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subuser/{id}"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -4,52 +4,77 @@ | ||||
|  | ||||
| #include "RESTAPI_subusers_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_subusers_handler::DoGet() { | ||||
|         std::vector<SecurityObjects::UserInfo> Users; | ||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); | ||||
|         bool IdOnly = GetBoolParameter("idOnly"); | ||||
|         auto operatorId = GetParameter("operatorId"); | ||||
|         auto nameSearch = GetParameter("nameSearch"); | ||||
|         auto emailSearch = GetParameter("emailSearch"); | ||||
|  | ||||
|         if(QB_.Select.empty()) { | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             Poco::JSON::Object Answer; | ||||
|             if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||
|                 for (auto &i : Users) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(i.id); | ||||
|                     } else { | ||||
|         std::string baseQuery; | ||||
|         if(!nameSearch.empty() || !emailSearch.empty()) { | ||||
|             if(!nameSearch.empty()) | ||||
|                 baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) ); | ||||
|             if(!emailSearch.empty()) | ||||
|                 baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch)) | ||||
|                 : fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch)); | ||||
|         } | ||||
|  | ||||
|         if(QB_.CountOnly) { | ||||
|             std::string whereClause; | ||||
|             if(!operatorId.empty()) { | ||||
|                 whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) : | ||||
|                               fmt::format(" owner='{}' and {} ", operatorId, baseQuery); | ||||
|                 auto count = StorageService()->SubDB().Count(whereClause); | ||||
|                 return ReturnCountOnly(count); | ||||
|             } | ||||
|             auto count = StorageService()->UserDB().Count(); | ||||
|             return ReturnCountOnly(count); | ||||
|         } else if(QB_.Select.empty()) { | ||||
|             std::string whereClause; | ||||
|             if(!operatorId.empty()) { | ||||
|                 whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) : | ||||
|                               fmt::format(" owner='{}' and {} ", operatorId, baseQuery); | ||||
|             } | ||||
|  | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, whereClause)) { | ||||
|                 for (auto &i : Users.users) { | ||||
|                     Sanitize(UserInfo_, i); | ||||
|                         i.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                 } | ||||
|             } | ||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|  | ||||
|             if(IdOnly) { | ||||
|                 Poco::JSON::Array   Arr; | ||||
|                 Poco::JSON::Object  Answer; | ||||
|  | ||||
|                 for(const auto &i:Users.users) { | ||||
|                     Arr.add(i.id); | ||||
|                 } | ||||
|                 Answer.set("users",Arr); | ||||
|                 return ReturnObject(Answer); | ||||
|             } | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } else { | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             for(auto &i:SelectedRecords()) { | ||||
|                 SecurityObjects::UserInfo   UInfo; | ||||
|                 auto tI{i}; | ||||
|                 if(StorageService()->SubDB().GetUserById(tI,UInfo)) { | ||||
|                 if(StorageService()->SubDB().GetUserById(i,UInfo)) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(UInfo.id); | ||||
|                     } else { | ||||
|                     Sanitize(UserInfo_, UInfo); | ||||
|                         UInfo.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     Users.users.emplace_back(UInfo); | ||||
|                 } | ||||
|             } | ||||
|             } | ||||
|             Poco::JSON::Object RetObj; | ||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             return ReturnObject(RetObj); | ||||
|             Poco::JSON::Object Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subusers"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subusers"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                           Server, | ||||
|                                                           TransactionId, | ||||
|                                                           Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/systemEndpoints"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/systemEndpoints"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -11,7 +11,6 @@ namespace OpenWifi { | ||||
|  | ||||
|         auto Reset = GetBoolParameter("reset",false); | ||||
|         std::string QRCode; | ||||
|  | ||||
|         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { | ||||
|             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); | ||||
|         } | ||||
| @@ -23,15 +22,14 @@ namespace OpenWifi { | ||||
|         auto nextIndex = GetParameter("index",0); | ||||
|         bool moreCodes=false; | ||||
|  | ||||
|         uint64_t ErrorCode = 0; | ||||
|         std::string ErrorText; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,false,Value,nextIndex,moreCodes, ErrorCode, ErrorText )) { | ||||
|         RESTAPI::Errors::msg Err; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,false,Value,nextIndex,moreCodes, Err)) { | ||||
|             Poco::JSON::Object Answer; | ||||
|             Answer.set("nextIndex", nextIndex); | ||||
|             Answer.set("moreCodes", moreCodes); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         return BadRequest(ErrorCode, ErrorText); | ||||
|         return BadRequest(Err); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                  Server, | ||||
|                                  TransactionId, | ||||
|                                  Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/totp"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/totp"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -4,8 +4,9 @@ | ||||
|  | ||||
| #include "RESTAPI_user_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "SMSSender.h" | ||||
| #include "SMTPMailerService.h" | ||||
| #include "ACLProcessor.h" | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -32,7 +33,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::JSON::Object  UserInfoObject; | ||||
| @@ -53,7 +54,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||
| @@ -64,18 +65,23 @@ namespace OpenWifi { | ||||
|         StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||
|         StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id); | ||||
|         StorageService()->UserTokenDB().RevokeAllTokens(Id); | ||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||
|         Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email)); | ||||
|         OK(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_user_handler::DoPost() { | ||||
|  | ||||
|         std::string Id = GetBinding("id", ""); | ||||
|         if(Id!="0") { | ||||
|             return BadRequest(RESTAPI::Errors::IdMustBe0); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         RESTAPI_utils::from_request(NewUser,*Request); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|         } | ||||
| @@ -87,7 +93,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::toLowerInPlace(NewUser.email); | ||||
| @@ -95,6 +101,11 @@ namespace OpenWifi { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   Existing; | ||||
|         if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) { | ||||
|             return BadRequest(RESTAPI::Errors::UserAlreadyExists); | ||||
|         } | ||||
|  | ||||
|         if(!NewUser.currentPassword.empty()) { | ||||
|             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { | ||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||
| @@ -109,20 +120,21 @@ namespace OpenWifi { | ||||
|         NewUser.userTypeProprietaryInfo.mfa.method = ""; | ||||
|         NewUser.userTypeProprietaryInfo.mobiles.clear(); | ||||
|         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|         NewUser.validated = true; | ||||
|  | ||||
|         if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) { | ||||
|             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); | ||||
|             Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email)); | ||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||
|         } | ||||
|  | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|         if(GetBoolParameter("email_verification")) { | ||||
|             if(AuthService::VerifyEmail(NewUser)) | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email)); | ||||
|             StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) { | ||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||
|             Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email)); | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
| @@ -130,10 +142,11 @@ namespace OpenWifi { | ||||
|         Sanitize(UserInfo_, NewUser); | ||||
|         NewUser.to_json(UserInfoObject); | ||||
|         ReturnObject(UserInfoObject); | ||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|         Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_user_handler::DoPut() { | ||||
|  | ||||
|         std::string Id = GetBinding("id", ""); | ||||
|         if(Id.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||
| @@ -145,11 +158,50 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("resetMFA")) { | ||||
|             if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) || | ||||
|                 (UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) || | ||||
|                 (UserInfo_.userinfo.id == Id)) { | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = false; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                 Existing.modified = OpenWifi::Now(); | ||||
|                 Existing.notes.push_back( SecurityObjects::NoteInfo{ | ||||
|                             .created=OpenWifi::Now(), | ||||
|                             .createdBy=UserInfo_.userinfo.email, | ||||
|                             .note="MFA Reset by " + UserInfo_.userinfo.email}); | ||||
|                 StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing); | ||||
|                 SecurityObjects::UserInfo   NewUserInfo; | ||||
|                 StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||
|                 Poco::JSON::Object  ModifiedObject; | ||||
|                 Sanitize(UserInfo_, NewUserInfo); | ||||
|                 NewUserInfo.to_json(ModifiedObject); | ||||
|                 return ReturnObject(ModifiedObject); | ||||
|             } else { | ||||
|                 return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("forgotPassword")) { | ||||
|             Existing.changePassword = true; | ||||
|             Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email)); | ||||
|             SecurityObjects::ActionLink NewLink; | ||||
|  | ||||
|             NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; | ||||
|             NewLink.id = MicroService::CreateUUID(); | ||||
|             NewLink.userId = Existing.id; | ||||
|             NewLink.created = OpenWifi::Now(); | ||||
|             NewLink.expires = NewLink.created + (24*60*60); | ||||
|             NewLink.userAction = true; | ||||
|             StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
|             return OK(); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         auto RawObject = ParseStream(); | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| @@ -178,10 +230,10 @@ namespace OpenWifi { | ||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||
|             if(NewRole!=Existing.userRole) { | ||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                 } | ||||
|                 if(Id==UserInfo_.userinfo.id) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                 } | ||||
|                 Existing.userRole = NewRole; | ||||
|             } | ||||
| @@ -191,7 +243,7 @@ namespace OpenWifi { | ||||
|             SecurityObjects::NoteInfoVec NIV; | ||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||
|             for(auto const &i:NIV) { | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 Existing.notes.push_back(ii); | ||||
|             } | ||||
|         } | ||||
| @@ -204,9 +256,9 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|         if(GetBoolParameter("email_verification")) { | ||||
|             if(AuthService::VerifyEmail(Existing)) | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email)); | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email)); | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("userTypeProprietaryInfo")) { | ||||
| @@ -215,23 +267,32 @@ namespace OpenWifi { | ||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||
|                 } | ||||
|  | ||||
|                 bool ChangingMFA = | ||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||
|  | ||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||
|                     if (PInfo->isArray("mobiles")) { | ||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||
|                     !SMSSender()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                 } | ||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || | ||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, | ||||
|                                                     UserInfo_.userinfo.email)) { | ||||
|  | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL && | ||||
|                     !SMTPMailerService()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::EMailMFANotEnabled); | ||||
|                 } | ||||
|  | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|  | ||||
|                 if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     if(NewUser.userTypeProprietaryInfo.mobiles.empty()) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles[0].verified = true; | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                     std::string Secret; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||
| @@ -241,13 +302,10 @@ namespace OpenWifi { | ||||
|                     } else { | ||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||
|                     } | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     // nothing to do for email. | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|             } else { | ||||
|                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
| @@ -255,6 +313,7 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Existing.modified = OpenWifi::Now(); | ||||
|         if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||
|             SecurityObjects::UserInfo   NewUserInfo; | ||||
|             StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/user/{id}"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -4,51 +4,55 @@ | ||||
|  | ||||
| #include "RESTAPI_users_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     void RESTAPI_users_handler::DoGet() { | ||||
|         std::vector<SecurityObjects::UserInfo> Users; | ||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); | ||||
|         auto nameSearch = GetParameter("nameSearch"); | ||||
|         auto emailSearch = GetParameter("emailSearch"); | ||||
|  | ||||
|         std::string baseQuery; | ||||
|         if(!nameSearch.empty() || !emailSearch.empty()) { | ||||
|             if(!nameSearch.empty()) | ||||
|                 baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) ); | ||||
|             if(!emailSearch.empty()) | ||||
|                 baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch)) | ||||
|                                                : fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch)); | ||||
|         } | ||||
|  | ||||
|         if(QB_.Select.empty()) { | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             Poco::JSON::Object Answer; | ||||
|             if (StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||
|                 for (auto &i : Users) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(i.id); | ||||
|                     } else { | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             if(StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, baseQuery)) { | ||||
|                 for (auto &i : Users.users) { | ||||
|                     Sanitize(UserInfo_, i); | ||||
|                         i.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                 } | ||||
|                 if(IdOnly) { | ||||
|                     Poco::JSON::Array   Arr; | ||||
|                     for(const auto &i:Users.users) | ||||
|                         Arr.add(i.id); | ||||
|                     Poco::JSON::Object  Answer; | ||||
|                     Answer.set("users", Arr); | ||||
|                     return ReturnObject(Answer); | ||||
|                 } | ||||
|             } | ||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             } | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } else { | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             for(auto &i:SelectedRecords()) { | ||||
|                 SecurityObjects::UserInfo   UInfo; | ||||
|                 auto tI{i}; | ||||
|                 if(StorageService()->UserDB().GetUserById(i,UInfo)) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(UInfo.id); | ||||
|                     } else { | ||||
|                     Sanitize(UserInfo_, UInfo); | ||||
|                         UInfo.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     Users.users.emplace_back(UInfo); | ||||
|                 } | ||||
|             } | ||||
|             } | ||||
|             Poco::JSON::Object RetObj; | ||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             return ReturnObject(RetObj); | ||||
|             Poco::JSON::Object Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                                   Server, | ||||
|                                   TransactionId, | ||||
|                                   Internal) {} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/users"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {}; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateSubToken"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/validateSubToken"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal) {}; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateToken"}; }; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/validateToken"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
							
								
								
									
										624
									
								
								src/RESTObjects/RESTAPI_AnalyticsObjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										624
									
								
								src/RESTObjects/RESTAPI_AnalyticsObjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,624 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-01-10. | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_AnalyticsObjects.h" | ||||
| #include "RESTAPI_ProvObjects.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
|  | ||||
| namespace OpenWifi::AnalyticsObjects { | ||||
|  | ||||
|     void Report::reset() { | ||||
|     } | ||||
|  | ||||
|     void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const { | ||||
|     } | ||||
|  | ||||
|     void VenueInfo::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,"retention",retention); | ||||
|         field_to_json(Obj,"interval",interval); | ||||
|         field_to_json(Obj,"monitorSubVenues",monitorSubVenues); | ||||
|     } | ||||
|  | ||||
|     bool VenueInfo::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,"retention",retention); | ||||
|             field_from_json(Obj,"interval",interval); | ||||
|             field_from_json(Obj,"monitorSubVenues",monitorSubVenues); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void BoardInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json(Obj,"venueList",venueList); | ||||
|     } | ||||
|  | ||||
|     bool BoardInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json(Obj,"venueList",venueList); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"boardId",boardId); | ||||
|         field_to_json(Obj,"type",type); | ||||
|         field_to_json(Obj,"serialNumber",serialNumber); | ||||
|         field_to_json(Obj,"deviceType",deviceType); | ||||
|         field_to_json(Obj,"lastContact",lastContact); | ||||
|         field_to_json(Obj,"lastPing",lastPing); | ||||
|         field_to_json(Obj,"lastState",lastState); | ||||
|         field_to_json(Obj,"lastFirmware",lastFirmware); | ||||
|         field_to_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate); | ||||
|         field_to_json(Obj,"lastConnection",lastConnection); | ||||
|         field_to_json(Obj,"lastDisconnection",lastDisconnection); | ||||
|         field_to_json(Obj,"pings",pings); | ||||
|         field_to_json(Obj,"states",states); | ||||
|         field_to_json(Obj,"connected",connected); | ||||
|         field_to_json(Obj,"connectionIp",connectionIp); | ||||
|         field_to_json(Obj,"associations_2g",associations_2g); | ||||
|         field_to_json(Obj,"associations_5g",associations_5g); | ||||
|         field_to_json(Obj,"associations_6g",associations_6g); | ||||
|         field_to_json(Obj,"health",health); | ||||
|         field_to_json(Obj,"lastHealth",lastHealth); | ||||
|         field_to_json(Obj,"locale",locale); | ||||
|         field_to_json(Obj,"uptime",uptime); | ||||
|         field_to_json(Obj,"memory",memory); | ||||
|     } | ||||
|  | ||||
|     bool DeviceInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"boardId",boardId); | ||||
|             field_from_json(Obj,"type",type); | ||||
|             field_from_json(Obj,"serialNumber",serialNumber); | ||||
|             field_from_json(Obj,"deviceType",deviceType); | ||||
|             field_from_json(Obj,"lastContact",lastContact); | ||||
|             field_from_json(Obj,"lastPing",lastPing); | ||||
|             field_from_json(Obj,"lastState",lastState); | ||||
|             field_from_json(Obj,"lastFirmware",lastFirmware); | ||||
|             field_from_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate); | ||||
|             field_from_json(Obj,"lastConnection",lastConnection); | ||||
|             field_from_json(Obj,"lastDisconnection",lastDisconnection); | ||||
|             field_from_json(Obj,"pings",pings); | ||||
|             field_from_json(Obj,"states",states); | ||||
|             field_from_json(Obj,"connected",connected); | ||||
|             field_from_json(Obj,"connectionIp",connectionIp); | ||||
|             field_from_json(Obj,"associations_2g",associations_2g); | ||||
|             field_from_json(Obj,"associations_5g",associations_5g); | ||||
|             field_from_json(Obj,"associations_6g",associations_6g); | ||||
|             field_from_json(Obj,"health",health); | ||||
|             field_from_json(Obj,"lastHealth",lastHealth); | ||||
|             field_from_json(Obj,"locale",locale); | ||||
|             field_from_json(Obj,"uptime",uptime); | ||||
|             field_from_json(Obj,"memory",memory); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"devices",devices); | ||||
|     } | ||||
|  | ||||
|     bool DeviceInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"devices",devices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void UE_rate::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"bitrate",bitrate); | ||||
|         field_to_json(Obj,"mcs",mcs); | ||||
|         field_to_json(Obj,"nss",nss); | ||||
|         field_to_json(Obj,"ht",ht); | ||||
|         field_to_json(Obj,"sgi",sgi); | ||||
|         field_to_json(Obj,"chwidth",chwidth); | ||||
|     } | ||||
|  | ||||
|     bool UE_rate::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"bitrate",bitrate); | ||||
|             field_from_json(Obj,"mcs",mcs); | ||||
|             field_from_json(Obj,"nss",nss); | ||||
|             field_from_json(Obj,"ht",ht); | ||||
|             field_from_json(Obj,"sgi",sgi); | ||||
|             field_from_json(Obj,"chwidth",chwidth); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void UETimePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"station",station); | ||||
|         field_to_json(Obj,"rssi",rssi); | ||||
|         field_to_json(Obj,"tx_bytes",tx_bytes); | ||||
|         field_to_json(Obj,"rx_bytes",rx_bytes); | ||||
|         field_to_json(Obj,"tx_duration",tx_duration); | ||||
|         field_to_json(Obj,"rx_packets",rx_packets); | ||||
|         field_to_json(Obj,"tx_packets",tx_packets); | ||||
|         field_to_json(Obj,"tx_retries",tx_retries); | ||||
|         field_to_json(Obj,"tx_failed",tx_failed); | ||||
|         field_to_json(Obj,"connected",connected); | ||||
|         field_to_json(Obj,"inactive",inactive); | ||||
|         field_to_json(Obj,"tx_rate",tx_rate); | ||||
|         field_to_json(Obj,"rx_rate",rx_rate); | ||||
| //      field_to_json(Obj, "tidstats", tidstats); | ||||
|  | ||||
|         field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|         field_to_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|         field_to_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|         field_to_json(Obj,"tx_failed_pct",tx_failed_pct); | ||||
|         field_to_json(Obj,"tx_retries_pct",tx_retries_pct); | ||||
|         field_to_json(Obj,"tx_duration_pct",tx_duration_pct); | ||||
|  | ||||
|         field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta); | ||||
|         field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta); | ||||
|         field_to_json(Obj,"tx_packets_delta",tx_packets_delta); | ||||
|         field_to_json(Obj,"rx_packets_delta",rx_packets_delta); | ||||
|         field_to_json(Obj,"tx_failed_delta",tx_failed_delta); | ||||
|         field_to_json(Obj,"tx_retries_delta",tx_retries_delta); | ||||
|         field_to_json(Obj,"tx_duration_delta",tx_duration_delta); | ||||
|     } | ||||
|  | ||||
|     bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"station",station); | ||||
|             field_from_json(Obj,"rssi",rssi); | ||||
|             field_from_json(Obj,"tx_bytes",tx_bytes); | ||||
|             field_from_json(Obj,"rx_bytes",rx_bytes); | ||||
|             field_from_json(Obj,"tx_duration",tx_duration); | ||||
|             field_from_json(Obj,"rx_packets",rx_packets); | ||||
|             field_from_json(Obj,"tx_packets",tx_packets); | ||||
|             field_from_json(Obj,"tx_retries",tx_retries); | ||||
|             field_from_json(Obj,"tx_failed",tx_failed); | ||||
|             field_from_json(Obj,"connected",connected); | ||||
|             field_from_json(Obj,"inactive",inactive); | ||||
|             field_from_json(Obj,"tx_rate",tx_rate); | ||||
|             field_from_json(Obj,"rx_rate",rx_rate); | ||||
| //          field_from_json(Obj,"tidstats",tidstats); | ||||
|             field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|             field_from_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|             field_from_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|             field_from_json(Obj,"tx_failed_pct",tx_failed_pct); | ||||
|             field_from_json(Obj,"tx_retries_pct",tx_retries_pct); | ||||
|             field_from_json(Obj,"tx_duration_pct",tx_duration_pct); | ||||
|             field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta); | ||||
|             field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta); | ||||
|             field_from_json(Obj,"tx_packets_delta",tx_packets_delta); | ||||
|             field_from_json(Obj,"rx_packets_delta",rx_packets_delta); | ||||
|             field_from_json(Obj,"tx_failed_delta",tx_failed_delta); | ||||
|             field_from_json(Obj,"tx_retries_delta",tx_retries_delta); | ||||
|             field_from_json(Obj,"tx_duration_delta",tx_duration_delta); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void APTimePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"collisions",collisions); | ||||
|         field_to_json(Obj,"multicast",multicast); | ||||
|         field_to_json(Obj,"rx_bytes",rx_bytes); | ||||
|         field_to_json(Obj,"rx_dropped",rx_dropped); | ||||
|         field_to_json(Obj,"rx_errors",rx_errors); | ||||
|         field_to_json(Obj,"rx_packets",rx_packets); | ||||
|         field_to_json(Obj,"tx_bytes",tx_bytes); | ||||
|         field_to_json(Obj,"tx_packets",tx_packets); | ||||
|         field_to_json(Obj,"tx_dropped",tx_dropped); | ||||
|         field_to_json(Obj,"tx_errors",tx_errors); | ||||
|         field_to_json(Obj,"tx_packets",tx_packets); | ||||
|  | ||||
|         field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct); | ||||
|         field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct); | ||||
|         field_to_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|         field_to_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|         field_to_json(Obj,"rx_errors_pct",rx_errors_pct); | ||||
|         field_to_json(Obj,"tx_errors_pct",tx_errors_pct); | ||||
|  | ||||
|         field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta); | ||||
|         field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta); | ||||
|         field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta); | ||||
|         field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta); | ||||
|         field_to_json(Obj,"rx_packets_delta",rx_packets_delta); | ||||
|         field_to_json(Obj,"tx_packets_delta",tx_packets_delta); | ||||
|         field_to_json(Obj,"rx_errors_delta",rx_errors_delta); | ||||
|         field_to_json(Obj,"tx_errors_delta",tx_errors_delta); | ||||
|     } | ||||
|  | ||||
|     bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"collisions",collisions); | ||||
|             field_from_json(Obj,"multicast",multicast); | ||||
|             field_from_json(Obj,"rx_bytes",rx_bytes); | ||||
|             field_from_json(Obj,"rx_dropped",rx_dropped); | ||||
|             field_from_json(Obj,"rx_errors",rx_errors); | ||||
|             field_from_json(Obj,"rx_packets",rx_packets); | ||||
|             field_from_json(Obj,"tx_bytes",tx_bytes); | ||||
|             field_from_json(Obj,"tx_packets",tx_packets); | ||||
|             field_from_json(Obj,"tx_dropped",tx_dropped); | ||||
|             field_from_json(Obj,"tx_errors",tx_errors); | ||||
|             field_from_json(Obj,"tx_packets",tx_packets); | ||||
|  | ||||
|             field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct); | ||||
|             field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct); | ||||
|             field_from_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|             field_from_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|             field_from_json(Obj,"rx_errors_pct",rx_errors_pct); | ||||
|             field_from_json(Obj,"tx_errors_pct",tx_errors_pct); | ||||
|  | ||||
|             field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta); | ||||
|             field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta); | ||||
|             field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta); | ||||
|             field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta); | ||||
|             field_from_json(Obj,"rx_packets_delta",rx_packets_delta); | ||||
|             field_from_json(Obj,"tx_packets_delta",tx_packets_delta); | ||||
|             field_from_json(Obj,"rx_errors_delta",rx_errors_delta); | ||||
|             field_from_json(Obj,"tx_errors_delta",tx_errors_delta); | ||||
|  | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void TIDstat_entry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"rx_msdu",rx_msdu); | ||||
|         field_to_json(Obj,"tx_msdu",tx_msdu); | ||||
|         field_to_json(Obj,"tx_msdu_failed",tx_msdu_failed); | ||||
|         field_to_json(Obj,"tx_msdu_retries",tx_msdu_retries); | ||||
|     } | ||||
|  | ||||
|     bool TIDstat_entry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"rx_msdu",rx_msdu); | ||||
|             field_from_json(Obj,"tx_msdu",tx_msdu); | ||||
|             field_from_json(Obj,"tx_msdu_failed",tx_msdu_failed); | ||||
|             field_from_json(Obj,"tx_msdu_retries",tx_msdu_retries); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"band",band); | ||||
|         field_to_json(Obj,"channel_width",channel_width); | ||||
|         field_to_json(Obj,"active_ms",active_ms); | ||||
|         field_to_json(Obj,"busy_ms",busy_ms); | ||||
|         field_to_json(Obj,"receive_ms",receive_ms); | ||||
|         field_to_json(Obj,"transmit_ms",transmit_ms); | ||||
|         field_to_json(Obj,"tx_power",tx_power); | ||||
|         field_to_json(Obj,"channel",channel); | ||||
|         field_to_json(Obj,"temperature",temperature); | ||||
|         field_to_json(Obj,"noise",noise); | ||||
|         field_to_json(Obj,"active_pct",active_pct); | ||||
|         field_to_json(Obj,"busy_pct",busy_pct); | ||||
|         field_to_json(Obj,"receive_pct",receive_pct); | ||||
|         field_to_json(Obj,"transmit_pct",transmit_pct); | ||||
|     } | ||||
|  | ||||
|     bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"band",band); | ||||
|             field_from_json(Obj,"channel_width",channel_width); | ||||
|             field_from_json(Obj,"active_ms",active_ms); | ||||
|             field_from_json(Obj,"busy_ms",busy_ms); | ||||
|             field_from_json(Obj,"receive_ms",receive_ms); | ||||
|             field_from_json(Obj,"transmit_ms",transmit_ms); | ||||
|             field_from_json(Obj,"tx_power",tx_power); | ||||
|             field_from_json(Obj,"channel",channel); | ||||
|             field_from_json(Obj,"temperature",temperature); | ||||
|             field_from_json(Obj,"noise",noise); | ||||
|             field_from_json(Obj,"active_pct",active_pct); | ||||
|             field_from_json(Obj,"busy_pct",busy_pct); | ||||
|             field_from_json(Obj,"receive_pct",receive_pct); | ||||
|             field_from_json(Obj,"transmit_pct",transmit_pct); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void AveragePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"min",min); | ||||
|         field_to_json(Obj,"max",max); | ||||
|         field_to_json(Obj,"avg",avg); | ||||
|     } | ||||
|  | ||||
|     bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"min",min); | ||||
|             field_from_json(Obj,"max",max); | ||||
|             field_from_json(Obj,"avg",avg); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SSIDTimePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"bssid",bssid); | ||||
|         field_to_json(Obj,"mode",mode); | ||||
|         field_to_json(Obj,"ssid",ssid); | ||||
|         field_to_json(Obj,"band",band); | ||||
|         field_to_json(Obj,"channel",channel); | ||||
|         field_to_json(Obj,"associations",associations); | ||||
|         field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|         field_to_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|         field_to_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|         field_to_json(Obj,"tx_failed_pct",tx_failed_pct); | ||||
|         field_to_json(Obj,"tx_retries_pct",tx_retries_pct); | ||||
|         field_to_json(Obj,"tx_duration_pct",tx_duration_pct); | ||||
|     } | ||||
|  | ||||
|     bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"bssid",bssid); | ||||
|             field_from_json(Obj,"mode",mode); | ||||
|             field_from_json(Obj,"ssid",ssid); | ||||
|             field_from_json(Obj,"band",band); | ||||
|             field_from_json(Obj,"channel",channel); | ||||
|             field_from_json(Obj,"associations",associations); | ||||
|             field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|             field_from_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|             field_from_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|             field_from_json(Obj,"tx_failed_pct",tx_failed_pct); | ||||
|             field_from_json(Obj,"tx_retries_pct",tx_retries_pct); | ||||
|             field_from_json(Obj,"tx_duration_pct",tx_duration_pct); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceTimePoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"id",id); | ||||
|         field_to_json(Obj,"boardId",boardId); | ||||
|         field_to_json(Obj,"timestamp",timestamp); | ||||
|         field_to_json(Obj,"ap_data",ap_data); | ||||
|         field_to_json(Obj,"ssid_data",ssid_data); | ||||
|         field_to_json(Obj,"radio_data",radio_data); | ||||
|         field_to_json(Obj,"device_info",device_info); | ||||
|         field_to_json(Obj,"serialNumber",serialNumber); | ||||
|     } | ||||
|  | ||||
|     bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"id",id); | ||||
|             field_from_json(Obj,"boardId",boardId); | ||||
|             field_from_json(Obj,"timestamp",timestamp); | ||||
|             field_from_json(Obj,"ap_data",ap_data); | ||||
|             field_from_json(Obj,"ssid_data",ssid_data); | ||||
|             field_from_json(Obj,"radio_data",radio_data); | ||||
|             field_from_json(Obj,"device_info",device_info); | ||||
|             field_from_json(Obj,"serialNumber",serialNumber); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"noise",noise); | ||||
|         field_to_json(Obj,"temperature",temperature); | ||||
|         field_to_json(Obj,"active_pct",active_pct); | ||||
|         field_to_json(Obj,"busy_pct",busy_pct); | ||||
|         field_to_json(Obj,"receive_pct",receive_pct); | ||||
|         field_to_json(Obj,"transmit_pct",transmit_pct); | ||||
|         field_to_json(Obj,"tx_power",tx_power); | ||||
|         field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|         field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct); | ||||
|         field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct); | ||||
|         field_to_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|         field_to_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|         field_to_json(Obj,"rx_errors_pct",rx_errors_pct); | ||||
|         field_to_json(Obj,"tx_errors_pct",tx_errors_pct); | ||||
|     } | ||||
|  | ||||
|     bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"noise",noise); | ||||
|             field_from_json(Obj,"temperature",temperature); | ||||
|             field_from_json(Obj,"active_pct",active_pct); | ||||
|             field_from_json(Obj,"busy_pct",busy_pct); | ||||
|             field_from_json(Obj,"receive_pct",receive_pct); | ||||
|             field_from_json(Obj,"transmit_pct",transmit_pct); | ||||
|             field_from_json(Obj,"tx_power",tx_power); | ||||
|             field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); | ||||
|             field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct); | ||||
|             field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct); | ||||
|             field_from_json(Obj,"rx_packets_bw",rx_packets_bw); | ||||
|             field_from_json(Obj,"tx_packets_bw",tx_packets_bw); | ||||
|             field_from_json(Obj,"rx_errors_pct",rx_errors_pct); | ||||
|             field_from_json(Obj,"tx_errors_pct",tx_errors_pct); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"points",points); | ||||
|         field_to_json(Obj,"stats",stats); | ||||
|     } | ||||
|  | ||||
|     bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"points",points); | ||||
|             field_from_json(Obj,"stats",stats); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceTimePointStats::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"firstPoint",firstPoint); | ||||
|         field_to_json(Obj,"lastPoint",lastPoint); | ||||
|         field_to_json(Obj,"count",count); | ||||
|     } | ||||
|  | ||||
|     bool DeviceTimePointStats::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"firstPoint",firstPoint); | ||||
|             field_from_json(Obj,"lastPoint",lastPoint); | ||||
|             field_from_json(Obj,"count",count); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void WifiClientRate::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"bitrate",bitrate); | ||||
|         field_to_json(Obj,"chwidth",chwidth); | ||||
|         field_to_json(Obj,"mcs",mcs); | ||||
|         field_to_json(Obj,"nss",nss); | ||||
|         field_to_json(Obj,"vht",vht); | ||||
|     } | ||||
|  | ||||
|     bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"bitrate",bitrate); | ||||
|             field_from_json(Obj,"chwidth",chwidth); | ||||
|             field_from_json(Obj,"mcs",mcs); | ||||
|             field_from_json(Obj,"nss",nss); | ||||
|             field_from_json(Obj,"vht",vht); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"timestamp",timestamp); | ||||
|         field_to_json(Obj,"station_id",station_id); | ||||
|         field_to_json(Obj,"bssid",bssid); | ||||
|         field_to_json(Obj,"ssid",ssid); | ||||
|         field_to_json(Obj,"rssi",rssi); | ||||
|         field_to_json(Obj,"rx_bitrate",rx_bitrate); | ||||
|         field_to_json(Obj,"rx_chwidth",rx_chwidth); | ||||
|         field_to_json(Obj,"rx_mcs",rx_mcs); | ||||
|         field_to_json(Obj,"rx_nss",rx_nss); | ||||
|         field_to_json(Obj,"rx_vht",rx_vht); | ||||
|         field_to_json(Obj,"tx_bitrate",tx_bitrate); | ||||
|         field_to_json(Obj,"tx_chwidth",tx_chwidth); | ||||
|         field_to_json(Obj,"tx_mcs",tx_mcs); | ||||
|         field_to_json(Obj,"tx_nss",tx_nss); | ||||
|         field_to_json(Obj,"tx_vht",tx_vht); | ||||
|         field_to_json(Obj,"rx_bytes",rx_bytes); | ||||
|         field_to_json(Obj,"tx_bytes",tx_bytes); | ||||
|         field_to_json(Obj,"rx_duration",rx_duration); | ||||
|         field_to_json(Obj,"tx_duration",tx_duration); | ||||
|         field_to_json(Obj,"rx_packets",rx_packets); | ||||
|         field_to_json(Obj,"tx_packets",tx_packets); | ||||
|         field_to_json(Obj,"ipv4",ipv4); | ||||
|         field_to_json(Obj,"ipv6",ipv6); | ||||
|         field_to_json(Obj,"channel_width",channel_width); | ||||
|         field_to_json(Obj,"noise",noise); | ||||
|         field_to_json(Obj,"tx_power",tx_power); | ||||
|         field_to_json(Obj,"channel",channel); | ||||
|         field_to_json(Obj,"active_ms",active_ms); | ||||
|         field_to_json(Obj,"busy_ms",busy_ms); | ||||
|         field_to_json(Obj,"receive_ms",receive_ms); | ||||
|         field_to_json(Obj,"mode",mode); | ||||
|         field_to_json(Obj,"ack_signal",ack_signal); | ||||
|         field_to_json(Obj,"ack_signal_avg",ack_signal_avg); | ||||
|         field_to_json(Obj,"connected",connected); | ||||
|         field_to_json(Obj,"inactive",inactive); | ||||
|         field_to_json(Obj,"tx_retries",tx_retries); | ||||
|         field_to_json(Obj,"venue_id",venue_id); | ||||
|     } | ||||
|  | ||||
|     bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"timestamp",timestamp); | ||||
|             field_from_json(Obj,"station_id",station_id); | ||||
|             field_from_json(Obj,"bssid",bssid); | ||||
|             field_from_json(Obj,"ssid",ssid); | ||||
|             field_from_json(Obj,"rssi",rssi); | ||||
|             field_from_json(Obj,"rx_bitrate",rx_bitrate); | ||||
|             field_from_json(Obj,"rx_chwidth",rx_chwidth); | ||||
|             field_from_json(Obj,"rx_mcs",rx_mcs); | ||||
|             field_from_json(Obj,"rx_nss",rx_nss); | ||||
|             field_from_json(Obj,"rx_vht",rx_vht); | ||||
|             field_from_json(Obj,"tx_bitrate",tx_bitrate); | ||||
|             field_from_json(Obj,"tx_chwidth",tx_chwidth); | ||||
|             field_from_json(Obj,"tx_mcs",tx_mcs); | ||||
|             field_from_json(Obj,"tx_nss",tx_nss); | ||||
|             field_from_json(Obj,"tx_vht",tx_vht); | ||||
|             field_from_json(Obj,"rx_bytes",rx_bytes); | ||||
|             field_from_json(Obj,"tx_bytes",tx_bytes); | ||||
|             field_from_json(Obj,"rx_duration",rx_duration); | ||||
|             field_from_json(Obj,"tx_duration",tx_duration); | ||||
|             field_from_json(Obj,"rx_packets",rx_packets); | ||||
|             field_from_json(Obj,"tx_packets",tx_packets); | ||||
|             field_from_json(Obj,"ipv4",ipv4); | ||||
|             field_from_json(Obj,"ipv6",ipv6); | ||||
|             field_from_json(Obj,"channel_width",channel_width); | ||||
|             field_from_json(Obj,"noise",noise); | ||||
|             field_from_json(Obj,"tx_power",tx_power); | ||||
|             field_from_json(Obj,"channel",channel); | ||||
|             field_from_json(Obj,"active_ms",active_ms); | ||||
|             field_from_json(Obj,"busy_ms",busy_ms); | ||||
|             field_from_json(Obj,"receive_ms",receive_ms); | ||||
|             field_from_json(Obj,"mode",mode); | ||||
|             field_from_json(Obj,"ack_signal",ack_signal); | ||||
|             field_from_json(Obj,"ack_signal_avg",ack_signal_avg); | ||||
|             field_from_json(Obj,"connected",connected); | ||||
|             field_from_json(Obj,"inactive",inactive); | ||||
|             field_from_json(Obj,"tx_retries",tx_retries); | ||||
|             field_from_json(Obj,"venue_id",venue_id); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										422
									
								
								src/RESTObjects/RESTAPI_AnalyticsObjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								src/RESTObjects/RESTAPI_AnalyticsObjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,422 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-01-10. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "RESTAPI_ProvObjects.h" | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     namespace AnalyticsObjects { | ||||
|  | ||||
|         struct Report { | ||||
|             uint64_t snapShot = 0; | ||||
|  | ||||
|             void reset(); | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|         }; | ||||
|  | ||||
|         struct VenueInfo { | ||||
|             OpenWifi::Types::UUID_t id; | ||||
|             std::string name; | ||||
|             std::string description; | ||||
|             uint64_t retention = 0; | ||||
|             uint64_t interval = 0; | ||||
|             bool monitorSubVenues = false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct BoardInfo { | ||||
|             ProvObjects::ObjectInfo info; | ||||
|             std::vector<VenueInfo> venueList; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|             inline bool operator<(const BoardInfo &bb) const { | ||||
|                 return info.id < bb.info.id; | ||||
|             } | ||||
|  | ||||
|             inline bool operator==(const BoardInfo &bb) const { | ||||
|                 return info.id == bb.info.id; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         struct DeviceInfo { | ||||
|             std::string boardId; | ||||
|             std::string type; | ||||
|             std::string serialNumber; | ||||
|             std::string deviceType; | ||||
|             uint64_t lastContact = 0 ; | ||||
|             uint64_t lastPing = 0; | ||||
|             uint64_t lastState = 0; | ||||
|             std::string lastFirmware; | ||||
|             uint64_t lastFirmwareUpdate = 0; | ||||
|             uint64_t lastConnection = 0; | ||||
|             uint64_t lastDisconnection = 0; | ||||
|             uint64_t pings = 0; | ||||
|             uint64_t states = 0; | ||||
|             bool connected = false; | ||||
|             std::string connectionIp; | ||||
|             uint64_t associations_2g = 0; | ||||
|             uint64_t associations_5g = 0; | ||||
|             uint64_t associations_6g = 0; | ||||
|             uint64_t health = 0; | ||||
|             uint64_t lastHealth = 0; | ||||
|             std::string locale; | ||||
|             uint64_t uptime = 0; | ||||
|             double memory = 0.0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct DeviceInfoList { | ||||
|             std::vector<DeviceInfo> devices; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum wifi_band { | ||||
|             band_2g = 0, band_5g = 1, band_6g = 2 | ||||
|         }; | ||||
|  | ||||
|         struct TIDstat_entry { | ||||
|             uint64_t rx_msdu = 0, | ||||
|                     tx_msdu = 0, | ||||
|                     tx_msdu_failed = 0, | ||||
|                     tx_msdu_retries = 0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UE_rate { | ||||
|             uint64_t    bitrate=0; | ||||
|             uint64_t    mcs=0; | ||||
|             uint64_t    nss=0; | ||||
|             bool        ht=false; | ||||
|             bool        sgi=false; | ||||
|             uint64_t    chwidth=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct AveragePoint { | ||||
|             double      min = 0.0, | ||||
|                         max = 0.0, | ||||
|                         avg = 0.0; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UETimePoint { | ||||
|             std::string station; | ||||
|             int64_t rssi = 0; | ||||
|             uint64_t tx_bytes = 0, | ||||
|                     rx_bytes = 0, | ||||
|                     tx_duration = 0, | ||||
|                     rx_packets = 0, | ||||
|                     tx_packets = 0, | ||||
|                     tx_retries = 0, | ||||
|                     tx_failed = 0, | ||||
|                     connected = 0, | ||||
|                     inactive = 0; | ||||
|  | ||||
|             double  tx_bytes_bw = 0.0 , | ||||
|                     rx_bytes_bw = 0.0 , | ||||
|                     tx_packets_bw = 0.0 , | ||||
|                     rx_packets_bw = 0.0 , | ||||
|                     tx_failed_pct = 0.0 , | ||||
|                     tx_retries_pct = 0.0 , | ||||
|                     tx_duration_pct = 0.0; | ||||
|  | ||||
|             uint64_t    tx_bytes_delta = 0, | ||||
|                         rx_bytes_delta = 0, | ||||
|                         tx_duration_delta = 0, | ||||
|                         rx_packets_delta = 0, | ||||
|                         tx_packets_delta = 0, | ||||
|                         tx_retries_delta = 0, | ||||
|                         tx_failed_delta = 0; | ||||
|  | ||||
|             UE_rate tx_rate, | ||||
|                     rx_rate; | ||||
|             std::vector<TIDstat_entry> tidstats; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum SSID_MODES { | ||||
|             unknown = 0, | ||||
|             ap, | ||||
|             mesh, | ||||
|             sta, | ||||
|             wds_ap, | ||||
|             wds_sta, | ||||
|             wds_repeater | ||||
|         }; | ||||
|  | ||||
|         inline SSID_MODES SSID_Mode(const std::string &m) { | ||||
|             if (m == "ap") | ||||
|                 return ap; | ||||
|             if (m == "sta") | ||||
|                 return sta; | ||||
|             if (m == "mesh") | ||||
|                 return mesh; | ||||
|             if (m == "wds-ap") | ||||
|                 return wds_ap; | ||||
|             if (m == "wds-sta") | ||||
|                 return wds_sta; | ||||
|             if (m == "wds-repeater") | ||||
|                 return wds_repeater; | ||||
|             return unknown; | ||||
|         } | ||||
|  | ||||
|         struct SSIDTimePoint { | ||||
|             std::string bssid, | ||||
|                         mode, | ||||
|                         ssid; | ||||
|             uint64_t    band=0, | ||||
|                         channel=0; | ||||
|             std::vector<UETimePoint> associations; | ||||
|  | ||||
|             AveragePoint    tx_bytes_bw, | ||||
|                             rx_bytes_bw, | ||||
|                             tx_packets_bw, | ||||
|                             rx_packets_bw, | ||||
|                             tx_failed_pct, | ||||
|                             tx_retries_pct, | ||||
|                             tx_duration_pct; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|  | ||||
|         struct APTimePoint { | ||||
|             uint64_t    collisions = 0, | ||||
|                         multicast = 0, | ||||
|                         rx_bytes = 0, | ||||
|                         rx_dropped = 0, | ||||
|                         rx_errors = 0, | ||||
|                         rx_packets = 0, | ||||
|                         tx_bytes = 0, | ||||
|                         tx_dropped = 0, | ||||
|                         tx_errors = 0, | ||||
|                         tx_packets = 0; | ||||
|  | ||||
|             double      tx_bytes_bw = 0.0 , | ||||
|                         rx_bytes_bw = 0.0 , | ||||
|                         rx_dropped_pct = 0.0, | ||||
|                         tx_dropped_pct = 0.0, | ||||
|                         rx_packets_bw = 0.0, | ||||
|                         tx_packets_bw = 0.0, | ||||
|                         rx_errors_pct = 0.0 , | ||||
|                         tx_errors_pct = 0.0; | ||||
|  | ||||
|             uint64_t    tx_bytes_delta = 0, | ||||
|                         rx_bytes_delta = 0 , | ||||
|                         rx_dropped_delta = 0, | ||||
|                         tx_dropped_delta = 0, | ||||
|                         rx_packets_delta = 0, | ||||
|                         tx_packets_delta = 0, | ||||
|                         rx_errors_delta = 0, | ||||
|                         tx_errors_delta = 0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct RadioTimePoint { | ||||
|             uint64_t    band = 0, | ||||
|                         channel_width = 0; | ||||
|             uint64_t    active_ms = 0, | ||||
|                         busy_ms = 0, | ||||
|                         receive_ms = 0, | ||||
|                         transmit_ms = 0, | ||||
|                         tx_power = 0, | ||||
|                         channel = 0; | ||||
|             int64_t     temperature = 0, | ||||
|                         noise = 0; | ||||
|  | ||||
|             double      active_pct = 0.0 , | ||||
|                         busy_pct = 0.0, | ||||
|                         receive_pct = 0.0, | ||||
|                         transmit_pct = 0.0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|  | ||||
|         struct DeviceTimePoint { | ||||
|             std::string                     id; | ||||
|             std::string                     boardId; | ||||
|             uint64_t                        timestamp = 0; | ||||
|             APTimePoint                     ap_data; | ||||
|             std::vector<SSIDTimePoint>      ssid_data; | ||||
|             std::vector<RadioTimePoint>     radio_data; | ||||
|             AnalyticsObjects::DeviceInfo    device_info; | ||||
|             std::string                     serialNumber; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|             inline bool operator<(const DeviceTimePoint &rhs) const { | ||||
|                 if(timestamp < rhs.timestamp) | ||||
|                     return true; | ||||
|                 if(timestamp > rhs.timestamp) | ||||
|                     return false; | ||||
|                 if(device_info.serialNumber < rhs.device_info.serialNumber) | ||||
|                     return true; | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             inline bool operator==(const DeviceTimePoint &rhs) const { | ||||
|                 return timestamp==rhs.timestamp && device_info.serialNumber==rhs.device_info.serialNumber; | ||||
|             } | ||||
|  | ||||
|             inline bool operator>(const DeviceTimePoint &rhs) const { | ||||
|                 if(timestamp > rhs.timestamp) | ||||
|                     return true; | ||||
|                 if(timestamp < rhs.timestamp) | ||||
|                     return false; | ||||
|                 if(device_info.serialNumber > rhs.device_info.serialNumber) | ||||
|                     return true; | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointAnalysis { | ||||
|             uint64_t        timestamp; | ||||
|  | ||||
|             AveragePoint    noise; | ||||
|             AveragePoint    temperature; | ||||
|             AveragePoint    active_pct; | ||||
|             AveragePoint    busy_pct; | ||||
|             AveragePoint    receive_pct; | ||||
|             AveragePoint    transmit_pct; | ||||
|             AveragePoint    tx_power; | ||||
|  | ||||
|             AveragePoint    tx_bytes_bw; | ||||
|             AveragePoint    rx_bytes_bw; | ||||
|             AveragePoint    rx_dropped_pct; | ||||
|             AveragePoint    tx_dropped_pct; | ||||
|             AveragePoint    rx_packets_bw; | ||||
|             AveragePoint    tx_packets_bw; | ||||
|             AveragePoint    rx_errors_pct; | ||||
|             AveragePoint    tx_errors_pct; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointList { | ||||
|             std::vector<DeviceTimePoint>            points; | ||||
|             std::vector<DeviceTimePointAnalysis>    stats; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct BandwidthAnalysisEntry { | ||||
|             uint64_t    timestamp = 0; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct BandwidthAnalysis { | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct AverageValueSigned { | ||||
|             int64_t     peak=0, avg=0, low=0; | ||||
|         }; | ||||
|  | ||||
|         struct AverageValueUnsigned { | ||||
|             uint64_t     peak=0, avg=0, low=0; | ||||
|         }; | ||||
|  | ||||
|         struct RadioAnalysis { | ||||
|             uint64_t                timestamp=0; | ||||
|             AverageValueSigned      noise, temperature; | ||||
|             AverageValueUnsigned    active_ms, | ||||
|                                     busy_ms, | ||||
|                                     transmit_ms, | ||||
|                                     receive_ms; | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointStats { | ||||
|             uint64_t                firstPoint=0; | ||||
|             uint64_t                lastPoint=0; | ||||
|             uint64_t                count=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct WifiClientRate { | ||||
|             uint32_t    bitrate=0; | ||||
|             uint32_t    chwidth=0; | ||||
|             uint16_t    mcs=0; | ||||
|             uint16_t    nss=0; | ||||
|             bool        vht=false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct WifiClientHistory { | ||||
|             uint64_t        timestamp=OpenWifi::Now(); | ||||
|             std::string     station_id; | ||||
|             std::string     bssid; | ||||
|             std::string     ssid; | ||||
|             int64_t         rssi=0; | ||||
|             uint32_t        rx_bitrate=0; | ||||
|             uint32_t        rx_chwidth=0; | ||||
|             uint16_t        rx_mcs=0; | ||||
|             uint16_t        rx_nss=0; | ||||
|             bool            rx_vht=false; | ||||
|             uint32_t        tx_bitrate=0; | ||||
|             uint32_t        tx_chwidth=0; | ||||
|             uint16_t        tx_mcs=0; | ||||
|             uint16_t        tx_nss=0; | ||||
|             bool            tx_vht=false; | ||||
|             uint64_t        rx_bytes=0; | ||||
|             uint64_t        tx_bytes=0; | ||||
|             uint64_t        rx_duration=0; | ||||
|             uint64_t        tx_duration=0; | ||||
|             uint64_t        rx_packets=0; | ||||
|             uint64_t        tx_packets=0; | ||||
|             std::string     ipv4; | ||||
|             std::string     ipv6; | ||||
|             uint64_t        channel_width=0; | ||||
|             int64_t         noise=0; | ||||
|             uint64_t        tx_power=0; | ||||
|             uint64_t        channel=0; | ||||
|             uint64_t        active_ms=0; | ||||
|             uint64_t        busy_ms=0; | ||||
|             uint64_t        receive_ms=0; | ||||
|             std::string     mode; | ||||
|             int64_t         ack_signal=0; | ||||
|             int64_t         ack_signal_avg=0; | ||||
|             uint64_t        connected=0; | ||||
|             uint64_t        inactive=0; | ||||
|             uint64_t        tx_retries=0; | ||||
|             std::string     venue_id; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -3,12 +3,12 @@ | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_CertObjects.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     namespace  CertObjects { | ||||
| namespace OpenWifi::CertObjects { | ||||
|     void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"id", id); | ||||
|         field_to_json(Obj,"entity", entity); | ||||
| @@ -29,6 +29,7 @@ namespace OpenWifi { | ||||
|         field_to_json(Obj,"modified", modified); | ||||
|         field_to_json(Obj,"revoked", revoked); | ||||
|         field_to_json(Obj,"revokeCount", revokeCount); | ||||
|         field_to_json(Obj,"synched", synched); | ||||
|     } | ||||
|  | ||||
|     bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -52,6 +53,7 @@ namespace OpenWifi { | ||||
|             field_from_json(Obj,"modified", modified); | ||||
|             field_from_json(Obj,"revoked", revoked); | ||||
|             field_from_json(Obj,"revokeCount", revokeCount); | ||||
|             field_from_json(Obj,"synched", synched); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -174,5 +176,33 @@ namespace OpenWifi { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "year", year); | ||||
|         field_to_json(Obj, "activeCerts", activeCerts); | ||||
|         field_to_json(Obj, "revokedCerts", revokedCerts); | ||||
|     } | ||||
|  | ||||
|     void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"snapshot", snapshot); | ||||
|         field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts); | ||||
|         field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts); | ||||
|         field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization); | ||||
|         field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization); | ||||
|         field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors); | ||||
|         field_to_json(Obj,"deviceTypes", deviceTypes); | ||||
|         field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts); | ||||
|         field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear); | ||||
|     } | ||||
|  | ||||
|     void Dashboard::reset() { | ||||
|         snapshot=0; | ||||
|         numberOfRevokedCerts = numberOfIssuedCerts = 0; | ||||
|         activeCertsPerOrganization.clear(); | ||||
|         revokedCertsPerOrganization.clear(); | ||||
|         numberOfRedirectors.clear(); | ||||
|         deviceTypes.clear(); | ||||
|         monthlyNumberOfCerts.clear(); | ||||
|         monthlyNumberOfCertsPerOrgPerYear.clear(); | ||||
|     } | ||||
| } | ||||
| @@ -5,13 +5,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     namespace CertObjects { | ||||
| namespace OpenWifi::CertObjects { | ||||
|  | ||||
|     struct CertificateEntry { | ||||
|         OpenWifi::Types::UUID_t         id; | ||||
| @@ -33,6 +30,7 @@ namespace OpenWifi { | ||||
|         uint64_t                        modified = 0; | ||||
|         uint64_t                        revoked = 0; | ||||
|         uint64_t                        revokeCount = 0; | ||||
|         uint64_t                        synched = 0; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -97,5 +95,28 @@ namespace OpenWifi { | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     } | ||||
|  | ||||
|     struct DashBoardYearlyStats { | ||||
|         uint64_t                            year=0; | ||||
|         OpenWifi::Types::Counted3DMapSII    activeCerts; | ||||
|         OpenWifi::Types::Counted3DMapSII    revokedCerts; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|     }; | ||||
|  | ||||
|     struct Dashboard { | ||||
|         uint64_t                            snapshot=0; | ||||
|         uint64_t                            numberOfIssuedCerts=0; | ||||
|         uint64_t                            numberOfRevokedCerts=0; | ||||
|         OpenWifi::Types::CountedMap         activeCertsPerOrganization; | ||||
|         OpenWifi::Types::CountedMap         revokedCertsPerOrganization; | ||||
|         OpenWifi::Types::CountedMap         numberOfRedirectors; | ||||
|         OpenWifi::Types::CountedMap         deviceTypes; | ||||
|         OpenWifi::Types::CountedMap         monthlyNumberOfCerts; | ||||
|         std::vector<DashBoardYearlyStats>   monthlyNumberOfCertsPerOrgPerYear; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         void reset(); | ||||
|     }; | ||||
|  | ||||
| } | ||||
| @@ -233,10 +233,10 @@ namespace OpenWifi::FMSObjects { | ||||
|         UnknownFirmwares_.clear(); | ||||
|         totalSecondsOld_.clear(); | ||||
|         numberOfDevices = 0 ; | ||||
|         snapshot = std::time(nullptr); | ||||
|         snapshot = OpenWifi::Now(); | ||||
|     } | ||||
|  | ||||
|     bool DeviceReport::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|  | ||||
|             return true; | ||||
| @@ -245,4 +245,65 @@ namespace OpenWifi::FMSObjects { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceInformation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "serialNumber",serialNumber); | ||||
|         field_to_json(Obj, "history", history); | ||||
|         field_to_json(Obj, "currentFirmware", currentFirmware); | ||||
|         field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmware", latestFirmware); | ||||
|         field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); | ||||
|         field_to_json(Obj, "latestFirmwareURI",latestFirmwareURI); | ||||
|     } | ||||
|  | ||||
|     bool DeviceInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "serialNumber",serialNumber); | ||||
|             field_from_json(Obj, "history", history); | ||||
|             field_from_json(Obj, "currentFirmware", currentFirmware); | ||||
|             field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmware", latestFirmware); | ||||
|             field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); | ||||
|             field_from_json(Obj, "latestFirmwareURI",latestFirmwareURI); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "serialNumber",serialNumber); | ||||
|         field_to_json(Obj, "revision", revision); | ||||
|         field_to_json(Obj, "upgraded", upgraded); | ||||
|     } | ||||
|  | ||||
|     bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "serialNumber",serialNumber); | ||||
|             field_from_json(Obj, "revision", revision); | ||||
|             field_from_json(Obj, "upgraded", upgraded); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "devices",devices); | ||||
|     } | ||||
|  | ||||
|     bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "devices",devices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,9 +4,7 @@ | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
| #define UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "RESTAPI_SecurityObjects.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| @@ -29,7 +27,7 @@ namespace OpenWifi::FMSObjects { | ||||
|         std::string     location; | ||||
|         std::string     uploader; | ||||
|         std::string     digest; | ||||
|         bool            latest=0; | ||||
|         bool            latest=false; | ||||
|         SecurityObjects::NoteInfoVec    notes; | ||||
|         uint64_t        created=0; | ||||
|  | ||||
| @@ -127,7 +125,35 @@ namespace OpenWifi::FMSObjects { | ||||
|         void reset(); | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceInformation { | ||||
|         std::string                 serialNumber; | ||||
|         RevisionHistoryEntryList    history; | ||||
|         std::string                 currentFirmware; | ||||
|         uint64_t                    currentFirmwareDate=0; | ||||
|         std::string                 latestFirmware; | ||||
|         uint64_t                    latestFirmwareDate=0; | ||||
|         bool                        latestFirmwareAvailable; | ||||
|         std::string                 latestFirmwareURI; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceCurrentInfo { | ||||
|         std::string                 serialNumber; | ||||
|         std::string                 revision; | ||||
|         uint64_t                    upgraded=0; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceCurrentInfoList { | ||||
|         std::vector<DeviceCurrentInfo>  devices; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
|   | ||||
| @@ -27,7 +27,7 @@ namespace OpenWifi::GWObjects { | ||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible)); | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); | ||||
| #endif | ||||
| 		field_to_json(Obj,"macAddress", MACAddress); | ||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||
| @@ -45,6 +45,10 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"compatible", Compatible); | ||||
| 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | ||||
| 		field_to_json(Obj,"devicePassword", DevicePassword); | ||||
| 		field_to_json(Obj,"subscriber", subscriber); | ||||
| 		field_to_json(Obj,"entity", entity); | ||||
| 		field_to_json(Obj,"modified", modified); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
| 	} | ||||
|  | ||||
| 	void Device::to_json_with_status(Poco::JSON::Object &Obj) const { | ||||
| @@ -69,7 +73,7 @@ namespace OpenWifi::GWObjects { | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	bool Device::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||
| 			field_from_json(Obj,"deviceType",DeviceType); | ||||
| @@ -81,6 +85,9 @@ namespace OpenWifi::GWObjects { | ||||
| 			field_from_json(Obj,"location",Location); | ||||
| 			field_from_json(Obj,"venue",Venue); | ||||
| 			field_from_json(Obj,"compatible",Compatible); | ||||
| 			field_from_json(Obj,"subscriber", subscriber); | ||||
| 			field_from_json(Obj,"entity", entity); | ||||
| 			field_from_json(Obj,"locale", locale); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| @@ -149,7 +156,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"executionTime", executionTime); | ||||
| 	} | ||||
|  | ||||
| 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",Name); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| @@ -168,7 +175,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"created", created); | ||||
| 	} | ||||
|  | ||||
| 	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"author",author); | ||||
| @@ -195,6 +202,11 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"websocketPackets", websocketPackets); | ||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); | ||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
| 		field_to_json(Obj,"started", started); | ||||
| 		field_to_json(Obj,"sessionId", sessionId); | ||||
| 		field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime); | ||||
| 		field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started); | ||||
|  | ||||
| 		switch(VerifiedCertificate) { | ||||
| 			case NO_CERTIFICATE: | ||||
| @@ -210,6 +222,21 @@ namespace OpenWifi::GWObjects { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"averageConnectionTime", averageConnectionTime); | ||||
| 		field_to_json(Obj,"connectedDevices", connectedDevices ); | ||||
| 	} | ||||
|  | ||||
| 	bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"averageConnectionTime", averageConnectionTime); | ||||
| 			field_from_json(Obj,"connectedDevices", connectedDevices ); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| 		field_to_json(Obj,"server", Server); | ||||
| @@ -256,7 +283,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		lastContact.clear(); | ||||
| 		associations.clear(); | ||||
| 		numberOfDevices = 0 ; | ||||
| 		snapshot = std::time(nullptr); | ||||
| 		snapshot = OpenWifi::Now(); | ||||
| 	} | ||||
|  | ||||
| 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | ||||
| @@ -264,5 +291,123 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"capabilities", capabilities); | ||||
| 	}; | ||||
|  | ||||
| 	void ScriptRequest::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber",serialNumber); | ||||
| 		field_to_json(Obj,"timeout",timeout); | ||||
| 		field_to_json(Obj,"type",type); | ||||
| 		field_to_json(Obj,"script",script); | ||||
| 		field_to_json(Obj,"scriptId",scriptId); | ||||
| 		field_to_json(Obj,"when",when); | ||||
| 	} | ||||
|  | ||||
| 	bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"timeout",timeout); | ||||
| 			field_from_json(Obj,"type",type); | ||||
| 			field_from_json(Obj,"script",script); | ||||
| 			field_from_json(Obj,"scriptId",scriptId); | ||||
| 			field_from_json(Obj,"when",when); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"pools",pools); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"pools",pools); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"name",name); | ||||
| 		field_to_json(Obj,"description",description); | ||||
| 		field_to_json(Obj,"authConfig",authConfig); | ||||
| 		field_to_json(Obj,"acctConfig",acctConfig); | ||||
| 		field_to_json(Obj,"coaConfig",coaConfig); | ||||
| 		field_to_json(Obj,"useByDefault",useByDefault); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",name); | ||||
| 			field_from_json(Obj,"description",description); | ||||
| 			field_from_json(Obj,"authConfig",authConfig); | ||||
| 			field_from_json(Obj,"acctConfig",acctConfig); | ||||
| 			field_from_json(Obj,"coaConfig",coaConfig); | ||||
| 			field_from_json(Obj,"useByDefault",useByDefault); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"strategy",strategy); | ||||
| 		field_to_json(Obj,"monitor",monitor); | ||||
| 		field_to_json(Obj,"monitorMethod",monitorMethod); | ||||
| 		field_to_json(Obj,"methodParameters",methodParameters); | ||||
| 		field_to_json(Obj,"servers",servers); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"strategy",strategy); | ||||
| 			field_from_json(Obj,"monitor",monitor); | ||||
| 			field_from_json(Obj,"monitorMethod",monitorMethod); | ||||
| 			field_from_json(Obj,"methodParameters",methodParameters); | ||||
| 			field_from_json(Obj,"servers",servers); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"name",name); | ||||
| 		field_to_json(Obj,"ip",ip); | ||||
| 		field_to_json(Obj,"port",port); | ||||
| 		field_to_json(Obj,"weight",weight); | ||||
| 		field_to_json(Obj,"secret",secret); | ||||
| 		field_to_json(Obj,"certificate",certificate); | ||||
| 		field_to_json(Obj,"radsec",radsec); | ||||
| 		field_to_json(Obj,"radsecPort",radsecPort); | ||||
| 		field_to_json(Obj,"radsecSecret",radsecSecret); | ||||
| 		field_to_json(Obj,"radsecCacerts",radsecCacerts); | ||||
| 		field_to_json(Obj,"radsecCert",radsecCert); | ||||
| 		field_to_json(Obj,"radsecKey",radsecKey); | ||||
| 		field_to_json(Obj,"radsecRealms",radsecRealms); | ||||
| 		field_to_json(Obj,"ignore",ignore); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",name); | ||||
| 			field_from_json(Obj,"ip",ip); | ||||
| 			field_from_json(Obj,"port",port); | ||||
| 			field_from_json(Obj,"weight",weight); | ||||
| 			field_from_json(Obj,"secret",secret); | ||||
| 			field_from_json(Obj,"certificate",certificate); | ||||
| 			field_from_json(Obj,"radsec",radsec); | ||||
| 			field_from_json(Obj,"radsecSecret",radsecSecret); | ||||
| 			field_from_json(Obj,"radsecPort",radsecPort); | ||||
| 			field_from_json(Obj,"radsecCacerts",radsecCacerts); | ||||
| 			field_from_json(Obj,"radsecCert",radsecCert); | ||||
| 			field_from_json(Obj,"radsecKey",radsecKey); | ||||
| 			field_from_json(Obj,"radsecRealms",radsecRealms); | ||||
| 			field_from_json(Obj,"ignore",ignore); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -37,6 +37,11 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t 	webSocketClients=0; | ||||
| 		uint64_t 	kafkaPackets=0; | ||||
| 		uint64_t 	websocketPackets=0; | ||||
| 		std::string locale; | ||||
| 		uint64_t 	started=0; | ||||
| 		uint64_t 	sessionId=0; | ||||
| 		double      connectionCompletionTime=0.0; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| @@ -59,12 +64,24 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t LastFWUpdate = 0 ; | ||||
| 		std::string Venue; | ||||
| 		std::string DevicePassword; | ||||
| 		std::string subscriber; | ||||
| 		std::string entity; | ||||
| 		uint64_t 	modified=0; | ||||
| 		std::string locale; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		void Print() const; | ||||
| 	}; | ||||
|  | ||||
| 	struct DeviceConnectionStatistics { | ||||
| 		std::uint64_t connectedDevices = 0; | ||||
| 		std::uint64_t averageConnectionTime = 0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct Statistics { | ||||
| 		std::string SerialNumber; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| @@ -118,7 +135,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t 	Created; | ||||
| 		uint64_t 	LastModified; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool 		from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool 		from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct CommandDetails { | ||||
| @@ -150,7 +167,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		std::string author; | ||||
| 		uint64_t created; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RttySessionDetails { | ||||
| @@ -193,4 +210,65 @@ namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct ScriptRequest { | ||||
| 		uint64_t 	timeout=30; | ||||
| 		std::string serialNumber; | ||||
| 		std::string type; | ||||
| 		std::string script; | ||||
| 		std::string scriptId; | ||||
| 		uint64_t 	when=0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyServerEntry { | ||||
| 		std::string name; | ||||
| 		std::string ip; | ||||
| 		uint16_t 	port=0; | ||||
| 		uint64_t 	weight=0; | ||||
| 		std::string secret; | ||||
| 		std::string certificate; | ||||
| 		bool 		radsec=false; | ||||
| 		uint16_t 	radsecPort=2083; | ||||
| 		std::string radsecSecret; | ||||
| 		std::string radsecKey; | ||||
| 		std::string radsecCert; | ||||
| 		std::vector<std::string> 	radsecCacerts; | ||||
| 		std::vector<std::string>	radsecRealms; | ||||
| 		bool 		ignore=false; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyServerConfig { | ||||
| 		std::string 	strategy; | ||||
| 		bool 			monitor=false; | ||||
| 		std::string 	monitorMethod; | ||||
| 		std::vector<std::string>	methodParameters; | ||||
| 		std::vector<RadiusProxyServerEntry>	servers; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct 	RadiusProxyPool { | ||||
| 		std::string name; | ||||
| 		std::string description; | ||||
| 		RadiusProxyServerConfig	authConfig; | ||||
| 		RadiusProxyServerConfig	acctConfig; | ||||
| 		RadiusProxyServerConfig	coaConfig; | ||||
| 		bool 		useByDefault=false; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyPoolList { | ||||
| 		std::vector<RadiusProxyPool>	pools; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
| } | ||||
|   | ||||
							
								
								
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2021-08-31. | ||||
| // | ||||
|  | ||||
| #include "framework/MicroService.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() { | ||||
|  | ||||
|     } | ||||
| } | ||||
							
								
								
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal 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 | ||||
| @@ -91,8 +91,13 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"devices",devices); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"sourceIP",sourceIP); | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|         field_to_json( Obj,"managementPolicies", managementPolicies); | ||||
|         field_to_json( Obj,"managementRoles", managementRoles); | ||||
|         field_to_json( Obj,"maps", maps); | ||||
|         field_to_json( Obj,"configurations", configurations); | ||||
|     } | ||||
|  | ||||
|     bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -106,8 +111,13 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"devices",devices); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"managementPolicies", managementPolicies); | ||||
|             field_from_json( Obj,"managementRoles", managementRoles); | ||||
|             field_from_json( Obj,"maps", maps); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -142,10 +152,16 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"design",design); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"contact",contact); | ||||
|         field_to_json( Obj,"contacts",contacts); | ||||
|         field_to_json( Obj,"location",location); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"sourceIP",sourceIP); | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|         field_to_json( Obj,"managementPolicies", managementPolicies); | ||||
|         field_to_json( Obj,"managementRoles", managementRoles); | ||||
|         field_to_json( Obj,"maps", maps); | ||||
|         field_to_json( Obj,"configurations", configurations); | ||||
|         field_to_json( Obj,"boards", boards); | ||||
|     } | ||||
|  | ||||
|     bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -160,10 +176,16 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"design",design); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"contact",contact); | ||||
|             field_from_json( Obj,"contacts",contacts); | ||||
|             field_from_json( Obj,"location",location); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"managementPolicies", managementPolicies); | ||||
|             field_from_json( Obj,"managementRoles", managementRoles); | ||||
|             field_from_json( Obj,"maps", maps); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             field_from_json( Obj,"boards", boards); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
| @@ -171,6 +193,89 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Operator::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"managementRoles",managementRoles); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"defaultOperator",defaultOperator); | ||||
|         field_to_json( Obj,"sourceIP",sourceIP); | ||||
|         field_to_json( Obj,"registrationId",registrationId); | ||||
|     } | ||||
|  | ||||
|     bool Operator::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"managementRoles",managementRoles); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"defaultOperator",defaultOperator); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"registrationId",registrationId); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"operators",operators); | ||||
|     } | ||||
|  | ||||
|     bool OperatorList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"operators",operators); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void ServiceClass::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"cost",cost); | ||||
|         field_to_json( Obj,"currency",currency); | ||||
|         field_to_json( Obj,"period",period); | ||||
|         field_to_json( Obj,"billingCode",billingCode); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"defaultService",defaultService); | ||||
|     } | ||||
|  | ||||
|     bool ServiceClass::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"cost",cost); | ||||
|             field_from_json( Obj,"currency",currency); | ||||
|             field_from_json( Obj,"period",period); | ||||
|             field_from_json( Obj,"billingCode",billingCode); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"defaultService",defaultService); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void ServiceClassList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"serviceClasses",serviceClasses); | ||||
|     } | ||||
|  | ||||
|     bool ServiceClassList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"serviceClasses",serviceClasses); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"id",id); | ||||
|         field_to_json( Obj,"entity",loginId); | ||||
| @@ -193,6 +298,7 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"users",users); | ||||
|         field_to_json( Obj,"entity",entity); | ||||
|         field_to_json( Obj,"venue",venue); | ||||
|     } | ||||
|  | ||||
|     bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -201,6 +307,7 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"users",users); | ||||
|             field_from_json( Obj,"entity",entity); | ||||
|             field_from_json( Obj,"venue",venue); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
| @@ -249,6 +356,92 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorLocation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type",type); | ||||
|         field_to_json( Obj,"buildingName",buildingName); | ||||
|         field_to_json( Obj,"addressLines",addressLines); | ||||
|         field_to_json( Obj,"city",city); | ||||
|         field_to_json( Obj,"state",state); | ||||
|         field_to_json( Obj,"postal",postal); | ||||
|         field_to_json( Obj,"country",country); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"geoCode",geoCode); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool OperatorLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"buildingName",buildingName); | ||||
|             field_from_json( Obj,"addressLines",addressLines); | ||||
|             field_from_json( Obj,"city",city); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"postal",postal); | ||||
|             field_from_json( Obj,"country",country); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"geoCode",geoCode); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubLocation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type",type); | ||||
|         field_to_json( Obj,"buildingName",buildingName); | ||||
|         field_to_json( Obj,"addressLines",addressLines); | ||||
|         field_to_json( Obj,"city",city); | ||||
|         field_to_json( Obj,"state",state); | ||||
|         field_to_json( Obj,"postal",postal); | ||||
|         field_to_json( Obj,"country",country); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"geoCode",geoCode); | ||||
|     } | ||||
|  | ||||
|     bool SubLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"buildingName",buildingName); | ||||
|             field_from_json( Obj,"addressLines",addressLines); | ||||
|             field_from_json( Obj,"city",city); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"postal",postal); | ||||
|             field_from_json( Obj,"country",country); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"geoCode",geoCode); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorLocationList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "locations", locations); | ||||
|     } | ||||
|  | ||||
|     bool OperatorLocationList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "locations", locations); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Contact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type", to_string(type)); | ||||
| @@ -295,21 +488,118 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorContact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"title",title); | ||||
|         field_to_json( Obj,"salutation",salutation); | ||||
|         field_to_json( Obj,"firstname",firstname); | ||||
|         field_to_json( Obj,"lastname",lastname); | ||||
|         field_to_json( Obj,"initials",initials); | ||||
|         field_to_json( Obj,"visual",visual); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"primaryEmail",primaryEmail); | ||||
|         field_to_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|         field_to_json( Obj,"accessPIN",accessPIN); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool OperatorContact::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"title",title); | ||||
|             field_from_json( Obj,"salutation",salutation); | ||||
|             field_from_json( Obj,"firstname",firstname); | ||||
|             field_from_json( Obj,"lastname",lastname); | ||||
|             field_from_json( Obj,"initials",initials); | ||||
|             field_from_json( Obj,"visual",visual); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"primaryEmail",primaryEmail); | ||||
|             field_from_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|             field_from_json( Obj,"accessPIN",accessPIN); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubContact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"title",title); | ||||
|         field_to_json( Obj,"salutation",salutation); | ||||
|         field_to_json( Obj,"firstname",firstname); | ||||
|         field_to_json( Obj,"lastname",lastname); | ||||
|         field_to_json( Obj,"initials",initials); | ||||
|         field_to_json( Obj,"visual",visual); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"primaryEmail",primaryEmail); | ||||
|         field_to_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|         field_to_json( Obj,"accessPIN",accessPIN); | ||||
|     } | ||||
|  | ||||
|     bool SubContact::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"title",title); | ||||
|             field_from_json( Obj,"salutation",salutation); | ||||
|             field_from_json( Obj,"firstname",firstname); | ||||
|             field_from_json( Obj,"lastname",lastname); | ||||
|             field_from_json( Obj,"initials",initials); | ||||
|             field_from_json( Obj,"visual",visual); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"primaryEmail",primaryEmail); | ||||
|             field_from_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|             field_from_json( Obj,"accessPIN",accessPIN); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorContactList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "contacts", contacts); | ||||
|     } | ||||
|  | ||||
|     bool OperatorContactList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "contacts", contacts); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void InventoryTag::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json(Obj, "serialNumber", serialNumber); | ||||
|         field_to_json(Obj, "venue", venue); | ||||
|         field_to_json(Obj, "entity", entity); | ||||
|         field_to_json(Obj, "subscriber", subscriber); | ||||
|         field_to_json(Obj, "deviceType", deviceType); | ||||
|         field_to_json(Obj, "qrCode", qrCode); | ||||
|         field_to_json(Obj, "geoCode", geoCode); | ||||
|         field_to_json(Obj, "location", location); | ||||
|         field_to_json(Obj, "contact", contact); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"state",state); | ||||
|         field_to_json( Obj, "serialNumber", serialNumber); | ||||
|         field_to_json( Obj, "venue", venue); | ||||
|         field_to_json( Obj, "entity", entity); | ||||
|         field_to_json( Obj, "subscriber", subscriber); | ||||
|         field_to_json( Obj, "deviceType", deviceType); | ||||
|         field_to_json( Obj, "qrCode", qrCode); | ||||
|         field_to_json( Obj, "geoCode", geoCode); | ||||
|         field_to_json( Obj, "location", location); | ||||
|         field_to_json( Obj, "contact", contact); | ||||
|         field_to_json( Obj, "deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj, "managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj, "state",state); | ||||
|         field_to_json( Obj, "devClass",devClass); | ||||
|         field_to_json( Obj, "locale",locale); | ||||
|         field_to_json( Obj, "realMacAddress",realMacAddress); | ||||
|     } | ||||
|  | ||||
|     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -320,14 +610,17 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"entity",entity); | ||||
|             field_from_json( Obj,"subscriber",subscriber); | ||||
|             field_from_json( Obj,"deviceType",deviceType); | ||||
|             field_from_json(Obj, "qrCode", qrCode); | ||||
|             field_from_json( Obj,"qrCode", qrCode); | ||||
|             field_from_json( Obj,"geoCode",geoCode); | ||||
|             field_from_json( Obj,"location",location); | ||||
|             field_from_json( Obj,"contact",contact); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"devClass",devClass); | ||||
|             field_from_json( Obj,"locale",locale); | ||||
|             field_from_json( Obj,"realMacAddress",realMacAddress); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -335,6 +628,26 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void InventoryConfigApplyResult::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||
|         field_to_json( Obj, "warnings", warnings); | ||||
|         field_to_json( Obj, "errors", errors); | ||||
|         field_to_json( Obj, "errorCode", errorCode); | ||||
|     } | ||||
|  | ||||
|     bool InventoryConfigApplyResult::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||
|             field_from_json( Obj, "warnings", warnings); | ||||
|             field_from_json( Obj, "errors", errors); | ||||
|             field_from_json( Obj, "errorCode", errorCode); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void InventoryTagList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"taglist",taglist); | ||||
|     } | ||||
| @@ -342,7 +655,7 @@ namespace OpenWifi::ProvObjects { | ||||
|     bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"taglist",taglist); | ||||
|             return false; | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
| @@ -373,12 +686,14 @@ namespace OpenWifi::ProvObjects { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceTypes",deviceTypes); | ||||
|         field_to_json( Obj,"subscriberOnly",subscriberOnly); | ||||
|         field_to_json( Obj,"entity", entity); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|         field_to_json( Obj,"subscriber", subscriber); | ||||
|         field_to_json( Obj,"configuration",configuration); | ||||
|         field_to_json( Obj,"inUse",inUse); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|         field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|     } | ||||
|  | ||||
|     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -386,12 +701,14 @@ namespace OpenWifi::ProvObjects { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceTypes",deviceTypes); | ||||
|             field_from_json( Obj,"configuration",configuration); | ||||
|             field_from_json( Obj,"inUse",inUse); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|             field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||
|             field_from_json( Obj,"subscriberOnly",subscriberOnly); | ||||
|             field_from_json( Obj,"entity", entity); | ||||
|             field_from_json( Obj,"venue", venue); | ||||
|             field_from_json( Obj,"subscriber", subscriber); | ||||
|             field_from_json( Obj,"configuration",configuration); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -470,46 +787,16 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, ACLACCESS A) { | ||||
|         switch(A) { | ||||
|             case READ: Obj.set(FieldName,"read"); break; | ||||
|             case MODIFY: Obj.set(FieldName,"modify"); break; | ||||
|             case CREATE: Obj.set(FieldName,"create"); break; | ||||
|             case DELETE: Obj.set(FieldName,"delete"); break; | ||||
|             case NONE: | ||||
|                 default: | ||||
|                     Obj.set(FieldName,"none"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, ACLACCESS &A) { | ||||
|         if(Obj->has(FieldName)) { | ||||
|             auto V = Obj->getValue<std::string>(FieldName); | ||||
|             if(V=="read") | ||||
|                 A = READ; | ||||
|             else if(V=="modify") | ||||
|                 A = MODIFY; | ||||
|             else if(V=="create") | ||||
|                 A = CREATE; | ||||
|             else if(V=="delete") | ||||
|                 A = DELETE; | ||||
|             else if(V=="none") | ||||
|                 A = NONE; | ||||
|             else | ||||
|                 throw Poco::Exception("invalid JSON"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { | ||||
|         RESTAPI_utils::field_to_json(Obj, "users", users); | ||||
|         RESTAPI_utils::field_to_json(Obj, "roles", roles); | ||||
|         field_to_json(Obj, "users", users); | ||||
|         field_to_json(Obj, "roles", roles); | ||||
|         field_to_json(Obj, "access", access); | ||||
|     } | ||||
|  | ||||
|     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             RESTAPI_utils::field_from_json(Obj, "users", users); | ||||
|             RESTAPI_utils::field_from_json(Obj, "roles", roles); | ||||
|             field_from_json(Obj, "users", users); | ||||
|             field_from_json(Obj, "roles", roles); | ||||
|             field_from_json(Obj, "access", access); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
| @@ -519,12 +806,12 @@ namespace OpenWifi::ProvObjects { | ||||
|     } | ||||
|      | ||||
|     void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         RESTAPI_utils::field_to_json(Obj, "list", list); | ||||
|         field_to_json(Obj, "list", list); | ||||
|     } | ||||
|  | ||||
|     bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             RESTAPI_utils::field_from_json(Obj, "list", list); | ||||
|             field_from_json(Obj, "list", list); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -532,44 +819,15 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     std::string to_string(VISIBILITY A) { | ||||
|         switch(A) { | ||||
|             case PUBLIC: return "public"; | ||||
|             case SELECT: return "select"; | ||||
|             case PRIVATE: | ||||
|             default: | ||||
|                 return "private"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, VISIBILITY A) { | ||||
|         Obj.set(FieldName,to_string(A)); | ||||
|     } | ||||
|  | ||||
|     VISIBILITY visibility_from_string(const std::string &V) { | ||||
|         if(V=="public") | ||||
|             return PUBLIC; | ||||
|         else if(V=="select") | ||||
|             return SELECT; | ||||
|         else if(V=="private") | ||||
|             return PRIVATE; | ||||
|         throw Poco::Exception("invalid json"); | ||||
|     } | ||||
|  | ||||
|     void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, VISIBILITY &A) { | ||||
|         if(Obj->has(FieldName)) { | ||||
|             auto V = Obj->getValue<std::string>(FieldName); | ||||
|             A = visibility_from_string(V); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void Map::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         RESTAPI_utils::field_to_json( Obj,"data",data); | ||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); | ||||
|         RESTAPI_utils::field_to_json( Obj,"creator",creator); | ||||
|         field_to_json( Obj,"data",data); | ||||
|         field_to_json( Obj,"entity",entity); | ||||
|         field_to_json( Obj,"creator",creator); | ||||
|         field_to_json( Obj,"visibility",visibility); | ||||
|         RESTAPI_utils::field_to_json( Obj,"access",access); | ||||
|         field_to_json( Obj,"access",access); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|     } | ||||
|  | ||||
|     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -578,8 +836,24 @@ namespace OpenWifi::ProvObjects { | ||||
|             RESTAPI_utils::field_from_json( Obj,"data",data); | ||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); | ||||
|             RESTAPI_utils::field_from_json( Obj,"creator",creator); | ||||
|             field_from_json( Obj,"visibility",visibility); | ||||
|             RESTAPI_utils::field_from_json( Obj,"visibility",visibility); | ||||
|             RESTAPI_utils::field_from_json( Obj,"access",access); | ||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             RESTAPI_utils::field_from_json( Obj,"venue", venue); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SerialNumberList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         RESTAPI_utils::field_to_json( Obj,"serialNumbers",serialNumbers); | ||||
|     } | ||||
|  | ||||
|     bool SerialNumberList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             RESTAPI_utils::field_from_json( Obj,"serialNumbers",serialNumbers); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -601,8 +875,223 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SignupEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"email", email); | ||||
|         field_to_json( Obj,"userId", userId); | ||||
|         field_to_json( Obj,"macAddress", macAddress); | ||||
|         field_to_json( Obj,"serialNumber", serialNumber); | ||||
|         field_to_json( Obj,"submitted", submitted); | ||||
|         field_to_json( Obj,"completed", completed); | ||||
|         field_to_json( Obj,"status", status); | ||||
|         field_to_json( Obj,"error", error); | ||||
|         field_to_json( Obj,"statusCode", statusCode); | ||||
|         field_to_json( Obj,"deviceID", deviceID); | ||||
|         field_to_json( Obj,"registrationId",registrationId); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|     } | ||||
|  | ||||
|     bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"email", email); | ||||
|             field_from_json( Obj,"userId", userId); | ||||
|             field_from_json( Obj,"macAddress", macAddress); | ||||
|             field_from_json( Obj,"serialNumber", serialNumber); | ||||
|             field_from_json( Obj,"submitted", submitted); | ||||
|             field_from_json( Obj,"completed", completed); | ||||
|             field_from_json( Obj,"status", status); | ||||
|             field_from_json( Obj,"error", error); | ||||
|             field_from_json( Obj,"statusCode", statusCode); | ||||
|             field_from_json( Obj,"deviceID", deviceID); | ||||
|             field_from_json( Obj,"registrationId",registrationId); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Variable::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"weight", weight); | ||||
|         field_to_json( Obj,"prefix", prefix); | ||||
|         field_to_json( Obj,"value", value); | ||||
|     } | ||||
|  | ||||
|     bool Variable::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"weight", weight); | ||||
|             field_from_json( Obj,"prefix", prefix); | ||||
|             field_from_json( Obj,"value", value); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|     } | ||||
|  | ||||
|     bool VariableList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableBlock::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|         field_to_json( Obj,"entity", entity); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|         field_to_json( Obj,"subscriber", subscriber); | ||||
|         field_to_json( Obj,"inventory", inventory); | ||||
|         field_to_json( Obj,"configurations", configurations); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool VariableBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"entity", entity); | ||||
|             field_from_json( Obj,"venue", venue); | ||||
|             field_from_json( Obj,"subscriber", subscriber); | ||||
|             field_from_json( Obj,"inventory", inventory); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableBlockList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"variableBlocks", variableBlocks); | ||||
|     } | ||||
|  | ||||
|     bool VariableBlockList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"variableBlocks", variableBlocks); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"configuration", configuration); | ||||
|         field_to_json( Obj,"rrm", rrm); | ||||
|         field_to_json( Obj,"firmwareRCOnly", firmwareRCOnly); | ||||
|         field_to_json( Obj,"firmwareUpgrade", firmwareUpgrade); | ||||
|     } | ||||
|  | ||||
|     bool ConfigurationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"configuration", configuration); | ||||
|             field_from_json( Obj,"rrm", rrm); | ||||
|             field_from_json( Obj,"firmwareRCOnly", firmwareRCOnly); | ||||
|             field_from_json( Obj,"firmwareUpgrade", firmwareUpgrade); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"serialNumber", serialNumber); | ||||
|         field_to_json( Obj,"deviceType", deviceType); | ||||
|         field_to_json( Obj,"operatorId", operatorId); | ||||
|         field_to_json( Obj,"subscriberId", subscriberId); | ||||
|         field_to_json( Obj,"location", location); | ||||
|         field_to_json( Obj,"contact", contact); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|         field_to_json( Obj,"serviceClass", serviceClass); | ||||
|         field_to_json( Obj,"qrCode", qrCode); | ||||
|         field_to_json( Obj,"geoCode", geoCode); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"state", state); | ||||
|         field_to_json( Obj,"locale", locale); | ||||
|         field_to_json( Obj,"billingCode", billingCode); | ||||
|         field_to_json( Obj,"configuration", configuration); | ||||
|         field_to_json( Obj,"suspended", suspended); | ||||
|         field_to_json( Obj,"realMacAddress", realMacAddress); | ||||
|     } | ||||
|  | ||||
|     bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"serialNumber", serialNumber); | ||||
|             field_from_json( Obj,"deviceType", deviceType); | ||||
|             field_from_json( Obj,"operatorId", operatorId); | ||||
|             field_from_json( Obj,"subscriberId", subscriberId); | ||||
|             field_from_json( Obj,"location", location); | ||||
|             field_from_json( Obj,"contact", contact); | ||||
|             field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             field_from_json( Obj,"serviceClass", serviceClass); | ||||
|             field_from_json( Obj,"qrCode", qrCode); | ||||
|             field_from_json( Obj,"geoCode", geoCode); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"state", state); | ||||
|             field_from_json( Obj,"locale", locale); | ||||
|             field_from_json( Obj,"billingCode", billingCode); | ||||
|             field_from_json( Obj,"configuration", configuration); | ||||
|             field_from_json( Obj,"suspended", suspended); | ||||
|             field_from_json( Obj,"realMacAddress", realMacAddress); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"subscriberDevices", subscriberDevices); | ||||
|     } | ||||
|  | ||||
|     bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"subscriberDevices", subscriberDevices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VenueDeviceList::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,"devices",devices); | ||||
|     } | ||||
|  | ||||
|     bool VenueDeviceList::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,"devices",devices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         if(O->has("name")) | ||||
|             I.name = O->get("name").toString(); | ||||
|  | ||||
| @@ -623,7 +1112,7 @@ namespace OpenWifi::ProvObjects { | ||||
|     } | ||||
|  | ||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         if(O->has("name")) | ||||
|             I.name = O->get("name").toString(); | ||||
|  | ||||
| @@ -645,5 +1134,30 @@ namespace OpenWifi::ProvObjects { | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         I.modified = I.created = OpenWifi::Now(); | ||||
|         I.id = MicroService::CreateUUID(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void DeviceRules::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"rcOnly",rcOnly); | ||||
|         field_to_json(Obj,"rrm",rrm); | ||||
|         field_to_json(Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|     } | ||||
|  | ||||
|     bool DeviceRules::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"rcOnly",rcOnly); | ||||
|             field_from_json(Obj,"rrm",rrm); | ||||
|             field_from_json(Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -33,6 +33,13 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SerialNumberList { | ||||
|         Types::UUIDvec_t    serialNumbers; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ManagementPolicyEntry { | ||||
|         Types::UUIDvec_t users; | ||||
|         Types::UUIDvec_t resources; | ||||
| @@ -48,12 +55,22 @@ namespace OpenWifi::ProvObjects { | ||||
|         std::vector<ManagementPolicyEntry>  entries; | ||||
|         Types::StringVec    inUse; | ||||
|         Types::UUID_t       entity; | ||||
|         Types::UUID_t       venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<ManagementPolicy>      ManagementPolicyVec; | ||||
|  | ||||
|     struct DeviceRules { | ||||
|         std::string     rcOnly{"inherit"}; | ||||
|         std::string     rrm{"inherit"}; | ||||
|         std::string     firmwareUpgrade{"inherit"}; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Entity { | ||||
|         ObjectInfo              info; | ||||
|         Types::UUID_t           parent; | ||||
| @@ -64,8 +81,13 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::UUID_t           managementPolicy; | ||||
|         Types::UUIDvec_t        deviceConfiguration; | ||||
|         Types::UUIDvec_t        devices; | ||||
|         std::string             rrm; | ||||
|         DeviceRules             deviceRules; | ||||
|         Types::StringVec        sourceIP; | ||||
|         Types::UUIDvec_t        variables; | ||||
|         Types::UUIDvec_t        managementPolicies; | ||||
|         Types::UUIDvec_t        managementRoles; | ||||
|         Types::UUIDvec_t        maps; | ||||
|         Types::UUIDvec_t        configurations; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -92,10 +114,16 @@ namespace OpenWifi::ProvObjects { | ||||
|         DiGraph             topology; | ||||
|         std::string         design; | ||||
|         Types::UUIDvec_t    deviceConfiguration; | ||||
|         std::string         contact; | ||||
|         Types::UUIDvec_t    contacts; | ||||
|         std::string         location; | ||||
|         std::string         rrm; | ||||
|         DeviceRules         deviceRules; | ||||
|         Types::StringVec    sourceIP; | ||||
|         Types::UUIDvec_t    variables; | ||||
|         Types::UUIDvec_t    configurations; | ||||
|         Types::UUIDvec_t    maps; | ||||
|         Types::UUIDvec_t    managementPolicies; | ||||
|         Types::UUIDvec_t    managementRoles; | ||||
|         Types::UUIDvec_t    boards; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -117,6 +145,7 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::UUIDvec_t    users; | ||||
|         Types::StringVec    inUse; | ||||
|         Types::UUID_t       entity; | ||||
|         Types::UUID_t       venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -180,6 +209,51 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|     typedef std::vector<Location>      LocationVec; | ||||
|  | ||||
|     struct OperatorLocation { | ||||
|         ObjectInfo          info; | ||||
|         std::string         type; | ||||
|         std::string         buildingName; | ||||
|         Types::StringVec    addressLines; | ||||
|         std::string         city; | ||||
|         std::string         state; | ||||
|         std::string         postal; | ||||
|         std::string         country; | ||||
|         Types::StringVec    phones; | ||||
|         Types::StringVec    mobiles; | ||||
|         std::string         geoCode; | ||||
|         Types::UUID_t       operatorId; | ||||
|         Types::UUID_t       subscriberDeviceId; | ||||
|         Types::UUID_t       managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<Location>      LocationVec; | ||||
|  | ||||
|     struct SubLocation { | ||||
|         std::string         type; | ||||
|         std::string         buildingName; | ||||
|         Types::StringVec    addressLines; | ||||
|         std::string         city; | ||||
|         std::string         state; | ||||
|         std::string         postal; | ||||
|         std::string         country; | ||||
|         Types::StringVec    phones; | ||||
|         Types::StringVec    mobiles; | ||||
|         std::string         geoCode; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorLocationList { | ||||
|         std::vector<OperatorLocation>    locations; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     enum ContactType { | ||||
|         CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER, | ||||
|         CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN | ||||
| @@ -243,6 +317,55 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|     typedef std::vector<Contact>      ContactVec; | ||||
|  | ||||
|     struct OperatorContact { | ||||
|         ObjectInfo      info; | ||||
|         std::string     type; | ||||
|         std::string     title; | ||||
|         std::string     salutation; | ||||
|         std::string     firstname; | ||||
|         std::string     lastname; | ||||
|         std::string     initials; | ||||
|         std::string     visual; | ||||
|         Types::StringVec mobiles; | ||||
|         Types::StringVec phones; | ||||
|         std::string     primaryEmail; | ||||
|         std::string     secondaryEmail; | ||||
|         std::string     accessPIN; | ||||
|         Types::UUID_t   operatorId; | ||||
|         Types::UUID_t   subscriberDeviceId; | ||||
|         Types::UUID_t   managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubContact { | ||||
|         std::string     type; | ||||
|         std::string     title; | ||||
|         std::string     salutation; | ||||
|         std::string     firstname; | ||||
|         std::string     lastname; | ||||
|         std::string     initials; | ||||
|         std::string     visual; | ||||
|         Types::StringVec mobiles; | ||||
|         Types::StringVec phones; | ||||
|         std::string     primaryEmail; | ||||
|         std::string     secondaryEmail; | ||||
|         std::string     accessPIN; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorContactList { | ||||
|         std::vector<OperatorContact>    contacts; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     typedef std::vector<OperatorContact>      OperatorContactVec; | ||||
|  | ||||
|     struct DeviceConfigurationElement { | ||||
|         std::string name; | ||||
|         std::string description; | ||||
| @@ -260,16 +383,19 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::StringVec                deviceTypes; | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         Types::StringVec                inUse; | ||||
|         Types::StringPairVec            variables; | ||||
|         std::string                     rrm; | ||||
|         std::string                     firmwareUpgrade; | ||||
|         bool                            firmwareRCOnly=false; | ||||
|         Types::UUIDvec_t                variables; | ||||
|         DeviceRules                     deviceRules; | ||||
|         bool                            subscriberOnly=false; | ||||
|         std::string                     venue; | ||||
|         std::string                     entity; | ||||
|         std::string                     subscriber; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<DeviceConfiguration>      DeviceConfigurationVec; | ||||
|  | ||||
|  | ||||
|     struct InventoryTag { | ||||
|         ObjectInfo      info; | ||||
|         std::string     serialNumber; | ||||
| @@ -282,9 +408,12 @@ namespace OpenWifi::ProvObjects { | ||||
|         std::string     location; | ||||
|         std::string     contact; | ||||
|         std::string     deviceConfiguration; | ||||
|         std::string     rrm; | ||||
|         DeviceRules     deviceRules; | ||||
|         Types::UUID_t   managementPolicy; | ||||
|         std::string     state; | ||||
|         std::string     devClass; | ||||
|         std::string     locale; | ||||
|         std::string     realMacAddress; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -299,6 +428,15 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct InventoryConfigApplyResult { | ||||
|         std::string         appliedConfiguration; | ||||
|         Types::StringVec    errors; | ||||
|         Types::StringVec    warnings; | ||||
|         uint64_t            errorCode; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Report { | ||||
|         uint64_t            snapShot=0; | ||||
| @@ -333,20 +471,20 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|  | ||||
|     struct UuidList { | ||||
|         std::vector<std::string>    list; | ||||
|         Types::UUIDvec_t    list; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum ACLACCESS { | ||||
|         NONE, READ, MODIFY, CREATE, DELETE | ||||
|         NONE = 0, READ=1, MODIFY=2, CREATE=3, DELETE=4 | ||||
|     }; | ||||
|  | ||||
|     struct ObjectACL { | ||||
|         UuidList        users; | ||||
|         UuidList        roles; | ||||
|         ACLACCESS       access = NONE; | ||||
|         uint64_t        access = (uint64_t) NONE; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -359,20 +497,15 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum VISIBILITY { | ||||
|         PUBLIC, PRIVATE, SELECT | ||||
|     }; | ||||
|  | ||||
|     std::string to_string(VISIBILITY A); | ||||
|     VISIBILITY visibility_from_string(const std::string &V); | ||||
|  | ||||
|     struct Map { | ||||
|         ObjectInfo          info; | ||||
|         std::string         data; | ||||
|         std::string         entity; | ||||
|         std::string         creator; | ||||
|         VISIBILITY          visibility = PRIVATE; | ||||
|         std::string         visibility{"private"}; | ||||
|         ObjectACLList       access; | ||||
|         Types::UUID_t       managementPolicy; | ||||
|         std::string         venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -385,6 +518,168 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum SignupStatusCodes { | ||||
|         SignupCreated = 0 , | ||||
|         SignupWaitingForEmail, | ||||
|         SignupWaitingForDevice, | ||||
|         SignupSuccess, | ||||
|         SignupFailure, | ||||
|         SignupCanceled, | ||||
|         SignupTimedOut | ||||
|     }; | ||||
|  | ||||
|     struct SignupEntry { | ||||
|         ObjectInfo          info; | ||||
|         std::string         email; | ||||
|         std::string         userId; | ||||
|         std::string         macAddress; | ||||
|         std::string         serialNumber; | ||||
|         uint64_t            submitted = 0 ; | ||||
|         uint64_t            completed = 0 ; | ||||
|         std::string         status; | ||||
|         uint64_t            error=0; | ||||
|         uint64_t            statusCode=0; | ||||
|         std::string         deviceID; | ||||
|         std::string         registrationId; | ||||
|         std::string         operatorId; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Variable { | ||||
|         std::string         type; | ||||
|         uint64_t            weight=0; | ||||
|         std::string         prefix; | ||||
|         std::string         value; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableList { | ||||
|         std::vector<Variable>   variables; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableBlock { | ||||
|         ObjectInfo                  info; | ||||
|         std::vector<Variable>       variables; | ||||
|         std::string                 entity; | ||||
|         std::string                 venue; | ||||
|         std::string                 subscriber; | ||||
|         std::string                 inventory; | ||||
|         Types::UUIDvec_t            configurations; | ||||
|         Types::UUID_t               managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableBlockList { | ||||
|         std::vector<VariableBlock>      variableBlocks; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Operator { | ||||
|         ObjectInfo                      info; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         Types::UUIDvec_t                managementRoles; | ||||
|         DeviceRules                     deviceRules; | ||||
|         std::vector<Variable>           variables; | ||||
|         bool                            defaultOperator=false; | ||||
|         Types::StringVec                sourceIP; | ||||
|         std::string                     registrationId; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorList { | ||||
|         std::vector<Operator>            operators; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VenueDeviceList { | ||||
|         std::string         id; | ||||
|         std::string         name; | ||||
|         std::string         description; | ||||
|         Types::UUIDvec_t    devices; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ServiceClass { | ||||
|         ObjectInfo                      info; | ||||
|         Types::UUID_t                   operatorId; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         double                          cost=0.0; | ||||
|         std::string                     currency; | ||||
|         std::string                     period; | ||||
|         std::string                     billingCode; | ||||
|         std::vector<Variable>           variables; | ||||
|         bool                            defaultService=false; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ServiceClassList { | ||||
|         std::vector<ServiceClass>            serviceClasses; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ConfigurationDetails { | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         std::string                     rrm{"inherit"}; | ||||
|         std::string                     firmwareUpgrade{"inherit"}; | ||||
|         std::string                     firmwareRCOnly{"inherit"}; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubscriberDevice { | ||||
|         ObjectInfo                      info; | ||||
|         std::string                     serialNumber; | ||||
|         std::string                     deviceType; | ||||
|         Types::UUID_t                   operatorId; | ||||
|         Types::UUID_t                   subscriberId; | ||||
|         SubLocation                     location; | ||||
|         SubContact                      contact; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         Types::UUID_t                   serviceClass; | ||||
|         std::string                     qrCode; | ||||
|         std::string                     geoCode; | ||||
|         DeviceRules                     deviceRules; | ||||
|         std::string                     state; | ||||
|         std::string                     locale; | ||||
|         std::string                     billingCode; | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         bool                            suspended=false; | ||||
|         std::string                     realMacAddress; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubscriberDeviceList { | ||||
|         std::vector<SubscriberDevice>       subscriberDevices; | ||||
|  | ||||
|         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 CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||
|     bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||
| }; | ||||
|   | ||||
| @@ -95,6 +95,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "PortalLogin", PortalLogin_); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: AclTemplate" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -112,6 +113,8 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"userMustChangePassword",userMustChangePassword); | ||||
|         field_to_json(Obj,"errorCode", errorCode); | ||||
| 		Obj.set("aclTemplate",AclTemplateObj); | ||||
|         field_to_json(Obj,"errorCode", errorCode); | ||||
|         field_to_json(Obj,"lastRefresh", lastRefresh_); | ||||
| 	} | ||||
|  | ||||
| 	bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -128,9 +131,10 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "created", created_); | ||||
| 			field_from_json(Obj, "username", username_); | ||||
|             field_from_json(Obj, "userMustChangePassword",userMustChangePassword); | ||||
|             field_from_json(Obj,"lastRefresh", lastRefresh_); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: WebToken" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -141,14 +145,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"primary", primary); | ||||
| 	} | ||||
|  | ||||
| 	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool MobilePhoneNumber::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"number",number); | ||||
| 	        field_from_json(Obj,"verified",verified); | ||||
| 	        field_from_json(Obj,"primary",primary); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: MobilePhoneNumber" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	}; | ||||
| @@ -158,13 +162,13 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"method", method); | ||||
| 	} | ||||
|  | ||||
| 	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool MfaAuthInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"enabled",enabled); | ||||
| 	        field_from_json(Obj,"method",method); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: MfaAuthInfo" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -175,14 +179,14 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj, "authenticatorSecret", authenticatorSecret); | ||||
| 	} | ||||
|  | ||||
| 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool UserLoginLoginExtensions::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj, "mobiles",mobiles); | ||||
| 	        field_from_json(Obj, "mfa",mfa); | ||||
|             field_from_json(Obj, "authenticatorSecret", authenticatorSecret); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: UserLoginLoginExtensions" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -194,7 +198,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj, "method", method); | ||||
|     } | ||||
|  | ||||
|     bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool MFAChallengeRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"uuid",uuid); | ||||
| 	        field_from_json(Obj,"question",question); | ||||
| @@ -202,7 +206,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	        field_from_json(Obj,"method",method); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: MFAChallengeRequest" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	}; | ||||
| @@ -210,16 +214,15 @@ namespace OpenWifi::SecurityObjects { | ||||
|     void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "uuid", uuid); | ||||
|         field_to_json(Obj, "answer", answer); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool MFAChallengeResponse::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"uuid",uuid); | ||||
|             field_from_json(Obj,"answer",answer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: MFAChallengeResponse" << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|  | ||||
| @@ -257,6 +260,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"oauthType",oauthType); | ||||
| 		field_to_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||
|         field_to_json(Obj,"modified",modified); | ||||
|         field_to_json(Obj,"signingUp",signingUp); | ||||
|     }; | ||||
|  | ||||
|     bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -292,13 +296,28 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"oauthType",oauthType); | ||||
| 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||
|             field_from_json(Obj,"modified",modified); | ||||
|             field_from_json(Obj,"signingUp",signingUp); | ||||
|             return true; | ||||
|         } catch (const Poco::Exception &E) { | ||||
|  | ||||
|             std::cout << "Cannot parse: UserInfo" << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|     }; | ||||
|  | ||||
|     void UserInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"users",users); | ||||
|     } | ||||
|  | ||||
|     bool UserInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"users",users); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|             std::cout << "Cannot parse: InternalServiceInfo" << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| 	void InternalServiceInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"privateURI",privateURI); | ||||
| 		field_to_json(Obj,"publicURI",publicURI); | ||||
| @@ -312,7 +331,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"token",token); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: InternalServiceInfo" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -330,7 +349,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "services", services); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: InternalSystemServices" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -352,7 +371,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "authenticationType", authenticationType); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: SystemEndpoint" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -366,7 +385,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "endpoints", endpoints); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: SystemEndpointList" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -385,7 +404,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "userInfo", userinfo); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: UserInfoAndPolicy" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -396,14 +415,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"note", note); | ||||
| 	} | ||||
|  | ||||
| 	bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool NoteInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
|             field_from_json(Obj,"created",created); | ||||
| 			field_from_json(Obj,"createdBy",createdBy); | ||||
| 			field_from_json(Obj,"note",note); | ||||
| 			field_from_json(Obj,"note", note); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: NoteInfo" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -414,20 +433,20 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	            SecurityObjects::NoteInfoVec NIV; | ||||
| 	            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString()); | ||||
| 	            for(auto const &i:NIV) { | ||||
| 	                SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	                SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	                Notes.push_back(ii); | ||||
| 	            } | ||||
| 	        } | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: MergeNotes" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
|  | ||||
| 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { | ||||
| 	    for(auto const &i:NewNotes) { | ||||
| 	        SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	        SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	        ExistingNotes.push_back(ii); | ||||
| 	    } | ||||
|         return true; | ||||
| @@ -438,13 +457,13 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); | ||||
| 	} | ||||
|  | ||||
| 	bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool ProfileAction::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"resource",resource); | ||||
| 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: ProfileAction" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -458,7 +477,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"notes", notes); | ||||
| 	} | ||||
|  | ||||
| 	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool SecurityProfile::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"id",id); | ||||
| 			field_from_json(Obj,"name",name); | ||||
| @@ -468,7 +487,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"notes",notes); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: SecurityProfile" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -477,12 +496,12 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj, "profiles", profiles); | ||||
| 	} | ||||
|  | ||||
| 	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool SecurityProfileList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"profiles",profiles); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: SecurityProfileList" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -503,7 +522,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"userAction",userAction); | ||||
| 	} | ||||
|  | ||||
|     bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool ActionLink::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"id",id); | ||||
| 	        field_from_json(Obj,"action",action); | ||||
| @@ -520,7 +539,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|             field_from_json(Obj,"userAction",userAction); | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: ActionLink" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -531,14 +550,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"data",data); | ||||
| 	} | ||||
|  | ||||
|     bool Preferences::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool Preferences::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"id",id); | ||||
| 	        field_from_json(Obj,"modified",modified); | ||||
| 	        field_from_json(Obj,"data",data); | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: Preferences" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -550,7 +569,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"email",email); | ||||
| 	} | ||||
|  | ||||
|     bool SubMfaConfig::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool SubMfaConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"id",id); | ||||
| 	        field_from_json(Obj,"type",type); | ||||
| @@ -558,7 +577,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	        field_from_json(Obj,"email",email); | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: SubMfaConfig" << std::endl; | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -572,9 +591,10 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"expires",expires); | ||||
|         field_to_json(Obj,"idleTimeout",idleTimeout); | ||||
|         field_to_json(Obj,"revocationDate",revocationDate); | ||||
|         field_to_json(Obj,"lastRefresh", lastRefresh); | ||||
|     } | ||||
|  | ||||
|     bool Token::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"token",token); | ||||
|             field_from_json(Obj,"refreshToken",refreshToken); | ||||
| @@ -584,9 +604,10 @@ namespace OpenWifi::SecurityObjects { | ||||
|             field_from_json(Obj,"expires",expires); | ||||
|             field_from_json(Obj,"idleTimeout",idleTimeout); | ||||
|             field_from_json(Obj,"revocationDate",revocationDate); | ||||
|             field_from_json(Obj,"lastRefresh", lastRefresh); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|             std::cout << "Cannot parse: Token" << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|   | ||||
| @@ -9,12 +9,14 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "Poco/JSON/Object.h" | ||||
| #include "Poco/Data/LOB.h" | ||||
| #include "Poco/Data/LOBStream.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     uint64_t Now(); | ||||
|     namespace SecurityObjects { | ||||
|          | ||||
|         typedef std::string USER_ID_TYPE; | ||||
| @@ -26,8 +28,13 @@ namespace OpenWifi { | ||||
|             bool Delete_ = true; | ||||
|             bool PortalLogin_ = true; | ||||
|  | ||||
|             AclTemplate()  noexcept = default; | ||||
|  | ||||
|             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); | ||||
|         }; | ||||
|  | ||||
|         static_assert( std::is_nothrow_move_constructible_v<AclTemplate> ); | ||||
|  | ||||
|         struct WebToken { | ||||
|             std::string access_token_; | ||||
| @@ -41,6 +48,7 @@ namespace OpenWifi { | ||||
|             uint64_t idle_timeout_=0; | ||||
|             AclTemplate acl_template_; | ||||
|             uint64_t created_=0; | ||||
|             uint64_t lastRefresh_=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -54,11 +62,12 @@ namespace OpenWifi { | ||||
|         std::string UserTypeToString(USER_ROLE U); | ||||
|  | ||||
|         struct NoteInfo { | ||||
|             uint64_t created = std::time(nullptr); | ||||
|             uint64_t    created=0; // = OpenWifi::Now(); | ||||
|             std::string createdBy; | ||||
|             std::string note; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<NoteInfo>	NoteInfoVec; | ||||
|  | ||||
| @@ -68,7 +77,7 @@ namespace OpenWifi { | ||||
|             bool primary = false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MfaAuthInfo { | ||||
| @@ -76,7 +85,7 @@ namespace OpenWifi { | ||||
|             std::string method; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UserLoginLoginExtensions { | ||||
| @@ -85,17 +94,17 @@ namespace OpenWifi { | ||||
|             std::string                     authenticatorSecret; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MFAChallengeRequest { | ||||
|             std::string uuid; | ||||
|             std::string question; | ||||
|             std::string method; | ||||
|             uint64_t    created = std::time(nullptr); | ||||
|             uint64_t    created = OpenWifi::Now(); | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MFAChallengeResponse { | ||||
| @@ -103,7 +112,7 @@ namespace OpenWifi { | ||||
|             std::string answer; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UserInfo { | ||||
| @@ -138,12 +147,20 @@ namespace OpenWifi { | ||||
|             std::string oauthType; | ||||
|             std::string oauthUserInfo; | ||||
|             uint64_t    modified; | ||||
|             std::string signingUp; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<UserInfo>   UserInfoVec; | ||||
|  | ||||
|         struct UserInfoList { | ||||
|             std::vector<UserInfo>   users; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||
|         bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||
|         bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); | ||||
| @@ -207,7 +224,7 @@ namespace OpenWifi { | ||||
|             std::string resource; | ||||
|             ResourceAccessType access; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<ProfileAction>	ProfileActionVec; | ||||
|  | ||||
| @@ -219,21 +236,23 @@ namespace OpenWifi { | ||||
|             std::string role; | ||||
|             NoteInfoVec notes; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<SecurityProfile> SecurityProfileVec; | ||||
|  | ||||
|         struct SecurityProfileList { | ||||
|             SecurityProfileVec profiles; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum LinkActions { | ||||
|             FORGOT_PASSWORD=1, | ||||
|             VERIFY_EMAIL, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_VERIFY_EMAIL | ||||
|             SUB_VERIFY_EMAIL, | ||||
|             SUB_SIGNUP, | ||||
|             EMAIL_INVITATION | ||||
|         }; | ||||
|  | ||||
|         struct ActionLink { | ||||
| @@ -245,14 +264,14 @@ namespace OpenWifi { | ||||
|             std::string         locale; | ||||
|             std::string         message; | ||||
|             uint64_t            sent=0; | ||||
|             uint64_t            created=std::time(nullptr); | ||||
|             uint64_t            created=OpenWifi::Now(); | ||||
|             uint64_t            expires=0; | ||||
|             uint64_t            completed=0; | ||||
|             uint64_t            canceled=0; | ||||
|             bool                userAction=true; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Preferences { | ||||
| @@ -260,7 +279,7 @@ namespace OpenWifi { | ||||
|             uint64_t                            modified; | ||||
|             Types::StringPairVec                data; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct SubMfaConfig { | ||||
| @@ -270,7 +289,7 @@ namespace OpenWifi { | ||||
|             std::string                         email; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Token { | ||||
| @@ -282,9 +301,10 @@ namespace OpenWifi { | ||||
|             uint64_t            expires=0; | ||||
|             uint64_t            idleTimeout=0; | ||||
|             uint64_t            revocationDate=0; | ||||
|             uint64_t            lastRefresh=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Avatar { | ||||
| @@ -292,7 +312,7 @@ namespace OpenWifi { | ||||
|             std::string             type; | ||||
|             uint64_t                created=0; | ||||
|             std::string             name; | ||||
|             Poco::Data::LOB<char>   avatar; | ||||
|             Poco::Data::BLOB        avatar; | ||||
|         }; | ||||
|  | ||||
|         struct LoginRecordInfo { | ||||
|   | ||||
| @@ -280,6 +280,7 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "ipv6", ipv6); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|         field_to_json(Obj, "manufacturer", manufacturer); | ||||
|     } | ||||
|  | ||||
|     bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -293,6 +294,7 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "ipv6", ipv6); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             field_from_json(Obj, "manufacturer", manufacturer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -324,6 +326,7 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "ipv6", ipv6); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|         field_to_json(Obj, "manufacturer", manufacturer); | ||||
|     } | ||||
|  | ||||
|     bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -335,6 +338,7 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "ipv6", ipv6); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             field_from_json(Obj, "manufacturer", manufacturer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -433,6 +437,8 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "rates", rates); | ||||
|         field_to_json(Obj, "he", he); | ||||
|         field_to_json(Obj, "rawInfo", rawInfo); | ||||
|         field_to_json(Obj, "allowDFS", allowDFS); | ||||
|         field_to_json(Obj, "mimo", mimo); | ||||
|     } | ||||
|  | ||||
|     bool RadioInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -452,6 +458,8 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "rates", rates); | ||||
|             field_from_json(Obj, "he", he); | ||||
|             field_from_json(Obj, "rawInfo", rawInfo); | ||||
|             field_from_json(Obj, "allowDFS", allowDFS); | ||||
|             field_from_json(Obj, "mimo", mimo); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -461,6 +469,7 @@ namespace OpenWifi::SubObjects { | ||||
|     void AccessPoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "id", id); | ||||
|         field_to_json(Obj, "macAddress", macAddress); | ||||
|         field_to_json(Obj, "serialNumber", serialNumber); | ||||
|         field_to_json(Obj, "name", name); | ||||
|         field_to_json(Obj, "deviceType", deviceType); | ||||
|         field_to_json(Obj, "subscriberDevices", subscriberDevices); | ||||
| @@ -473,12 +482,19 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "radios", radios); | ||||
|         field_to_json(Obj, "automaticUpgrade", automaticUpgrade); | ||||
|         field_to_json(Obj, "configurationUUID", configurationUUID); | ||||
|         field_to_json(Obj, "currentFirmware", currentFirmware); | ||||
|         field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmware", latestFirmware); | ||||
|         field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|         field_to_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); | ||||
|         field_to_json(Obj, "latestFirmwareURI", latestFirmwareURI); | ||||
|     } | ||||
|  | ||||
|     bool AccessPoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "id", id); | ||||
|             field_from_json(Obj, "macAddress", macAddress); | ||||
|             field_from_json(Obj, "serialNumber", serialNumber); | ||||
|             field_from_json(Obj, "name", name); | ||||
|             field_from_json(Obj, "deviceType", deviceType); | ||||
|             field_from_json(Obj, "subscriberDevices", subscriberDevices); | ||||
| @@ -491,6 +507,12 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "radios", radios); | ||||
|             field_from_json(Obj, "automaticUpgrade", automaticUpgrade); | ||||
|             field_from_json(Obj, "configurationUUID", configurationUUID); | ||||
|             field_from_json(Obj, "currentFirmware", currentFirmware); | ||||
|             field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmware", latestFirmware); | ||||
|             field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|             field_from_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); | ||||
|             field_from_json(Obj, "latestFirmwareURI", latestFirmwareURI); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -544,4 +566,38 @@ namespace OpenWifi::SubObjects { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void StatsEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "timestamp", timestamp); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|     } | ||||
|  | ||||
|     bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "timestamp", timestamp); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void StatsBlock::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "modified", modified); | ||||
|         field_to_json(Obj, "external", external); | ||||
|         field_to_json(Obj, "internal", internal); | ||||
|     } | ||||
|  | ||||
|     bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "modified", modified); | ||||
|             field_from_json(Obj, "external", external); | ||||
|             field_from_json(Obj, "internal", internal); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -24,6 +24,7 @@ namespace OpenWifi::SubObjects { | ||||
|         int             subnetMaskV6=0; | ||||
|         std::string     startIPV6; | ||||
|         std::string     endIPV6; | ||||
|         std::string     leaseTime; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -156,6 +157,7 @@ namespace OpenWifi::SubObjects { | ||||
|         std::string     ipv6; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|         std::string     manufacturer; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -178,6 +180,7 @@ namespace OpenWifi::SubObjects { | ||||
|         std::string     ipv6; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|         std::string     manufacturer; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -238,6 +241,8 @@ namespace OpenWifi::SubObjects { | ||||
|         uint64_t                maximumClients = 64; | ||||
|         RadioRates              rates; | ||||
|         RadioHE                 he; | ||||
|         bool                    allowDFS=false; | ||||
|         std::string             mimo; | ||||
|         std::vector<std::string>    rawInfo; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
| @@ -247,6 +252,7 @@ namespace OpenWifi::SubObjects { | ||||
|     struct AccessPoint { | ||||
|         std::string                 id; | ||||
|         std::string                 macAddress; | ||||
|         std::string                 serialNumber; | ||||
|         std::string                 name; | ||||
|         std::string                 deviceType; | ||||
|         SubscriberDeviceList        subscriberDevices; | ||||
| @@ -259,6 +265,12 @@ namespace OpenWifi::SubObjects { | ||||
|         std::vector<RadioInformation>   radios; | ||||
|         bool                        automaticUpgrade = true; | ||||
|         std::string                 configurationUUID; | ||||
|         std::string                 currentFirmware; | ||||
|         uint64_t                    currentFirmwareDate; | ||||
|         std::string                 latestFirmware; | ||||
|         uint64_t                    latestFirmwareDate; | ||||
|         bool                        newFirmwareAvailable; | ||||
|         std::string                 latestFirmwareURI; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -288,6 +300,23 @@ namespace OpenWifi::SubObjects { | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct StatsEntry { | ||||
|         uint64_t        timestamp=0; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct StatsBlock { | ||||
|         uint64_t                    modified=0; | ||||
|         std::vector<StatsEntry>     external, internal; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #endif //OWSUB_RESTAPI_SUBOBJECTS_H | ||||
|   | ||||
| @@ -2,16 +2,14 @@ | ||||
| // Created by stephane bourque on 2021-10-09. | ||||
| // | ||||
|  | ||||
| #include <aws/sns/SNSClient.h> | ||||
| #include <aws/sns/model/PublishRequest.h> | ||||
| #include <aws/sns/model/PublishResult.h> | ||||
| #include <aws/sns/model/GetSMSAttributesRequest.h> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "MFAServer.h" | ||||
| #include "SMS_provider_aws.h" | ||||
| #include "SMS_provider_twilio.h" | ||||
| #include "SMSSender.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -34,7 +32,7 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void SMSSender::CleanCache() { | ||||
|         uint64_t Now=std::time(nullptr); | ||||
|         uint64_t Now=OpenWifi::Now(); | ||||
|         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||
|             if((Now-i->Created)>300) | ||||
|                 i = Cache_.erase(i); | ||||
| @@ -45,8 +43,10 @@ namespace OpenWifi { | ||||
|  | ||||
|     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|         CleanCache(); | ||||
|         uint64_t Now=std::time(nullptr); | ||||
|         uint64_t Now=OpenWifi::Now(); | ||||
|         auto Challenge = MFAServer::MakeChallenge(); | ||||
|         Cache_.emplace_back(SMSValidationCacheEntry{.Number=Number, .Code=Challenge, .UserName=UserName, .Created=Now}); | ||||
|         std::string Message = "Please enter the following code on your login screen: " + Challenge; | ||||
| @@ -56,6 +56,9 @@ namespace OpenWifi { | ||||
|     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|  | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|  | ||||
|         for(const auto &i:Cache_) { | ||||
|             if(i.Number==Number && i.UserName==UserName) | ||||
|                 return i.Validated; | ||||
| @@ -66,6 +69,9 @@ namespace OpenWifi { | ||||
|     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|  | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|  | ||||
|         for(auto &i:Cache_) { | ||||
|             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { | ||||
|                 i.Validated=true; | ||||
| @@ -77,7 +83,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { | ||||
|         if(!Enabled_) { | ||||
|             Logger().information("SMS has not been enabled. Messages cannot be sent."); | ||||
|             poco_information(Logger(),"SMS has not been enabled. Messages cannot be sent."); | ||||
|             return false; | ||||
|         } | ||||
|         return ProviderImpl_->Send(PhoneNumber,Message); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|         std::string Number; | ||||
|         std::string Code; | ||||
|         std::string UserName; | ||||
|         uint64_t    Created = std::time(nullptr); | ||||
|         uint64_t    Created = OpenWifi::Now(); | ||||
|         bool        Validated = false; | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|         Region_ = MicroService::instance().ConfigGetString("smssender.aws.region",""); | ||||
|  | ||||
|         if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) { | ||||
|             Logger().debug("SMSSender is disabled. Please provide key, secret, and region."); | ||||
|             poco_debug(Logger(),"SMSSender is disabled. Please provide key, secret, and region."); | ||||
|             return false; | ||||
|         } | ||||
|         Running_=true; | ||||
| @@ -51,16 +51,16 @@ namespace OpenWifi { | ||||
|  | ||||
|             auto psms_out = sns.Publish(psms_req); | ||||
|             if (psms_out.IsSuccess()) { | ||||
|                 Logger().debug(Poco::format("SMS sent to %s",PhoneNumber)); | ||||
|                 poco_debug(Logger(),fmt::format("SMS sent to {}",PhoneNumber)); | ||||
|                 return true; | ||||
|             } | ||||
|             std::string ErrMsg{psms_out.GetError().GetMessage()}; | ||||
|             Logger().debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); | ||||
|             poco_debug(Logger(),fmt::format("SMS NOT sent to {}: {}",PhoneNumber, ErrMsg)); | ||||
|             return false; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         Logger().debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); | ||||
|         poco_debug(Logger(),fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber)); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -4,12 +4,13 @@ | ||||
|  | ||||
| #include "SMS_provider_twilio.h" | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "Poco/Net/HTTPBasicCredentials.h" | ||||
| #include "Poco/URI.h" | ||||
| #include "Poco/Net/HTMLForm.h" | ||||
| #include "Poco/Net/HTTPSClientSession.h" | ||||
| #include "Poco/Net/HTTPResponse.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     bool SMS_provider_twilio::Initialize() { | ||||
| @@ -18,7 +19,7 @@ namespace OpenWifi { | ||||
|         PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); | ||||
|  | ||||
|         if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { | ||||
|             Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); | ||||
|             poco_debug(Logger(),"SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); | ||||
|             return false; | ||||
|         } | ||||
|         Running_=true; | ||||
| @@ -52,9 +53,9 @@ namespace OpenWifi { | ||||
|  | ||||
|         Poco::JSON::Object  RObj; | ||||
|  | ||||
|         form.add("To",PhoneNumber); | ||||
|         form.add("From",PhoneNumber_); | ||||
|         form.add("Body","This is from twillio"); | ||||
|         form.add("To", PhoneNumber); | ||||
|         form.add("From", PhoneNumber_); | ||||
|         form.add("Body", Message); | ||||
|  | ||||
|         form.prepareSubmit(req); | ||||
|         std::ostream& ostr = session.sendRequest(req); | ||||
| @@ -64,12 +65,12 @@ namespace OpenWifi { | ||||
|         std::istream& rs = session.receiveResponse(res); | ||||
|  | ||||
|         if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||
|             Logger().information(Poco::format("Message sent to %s", PhoneNumber)); | ||||
|             poco_information(Logger(),fmt::format("Message sent to {}", PhoneNumber)); | ||||
|             return true; | ||||
|         } else { | ||||
|             std::ostringstream os; | ||||
|             Poco::StreamCopier::copyStream(rs,os); | ||||
|             Logger().information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str())); | ||||
|             poco_information(Logger(),fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str())); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -2,7 +2,8 @@ | ||||
| // Created by stephane bourque on 2021-06-17. | ||||
| // | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "Poco/Net/MailMessage.h" | ||||
| #include "Poco/Net/MailRecipient.h" | ||||
| @@ -12,9 +13,9 @@ | ||||
| #include "Poco/Exception.h" | ||||
| #include "Poco/Net/SSLManager.h" | ||||
| #include "Poco/Net/Context.h" | ||||
| #include "Poco/Net/NetException.h" | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "AuthService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| @@ -27,11 +28,13 @@ namespace OpenWifi { | ||||
|             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); | ||||
|             Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); | ||||
|             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); | ||||
|             MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); | ||||
|             MailHostPort_ = MicroService::instance().ConfigGetInt("mailer.port"); | ||||
|             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); | ||||
|             MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||
|             MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||
|             MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||
|             MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||
|             UseHTML_ = MicroService::instance().ConfigGetBool("mailer.html",false); | ||||
|             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||
|             EmailLogo_ = TemplateDir_ + "/" + MicroService::instance().ConfigGetString("mailer.logo","logo.jpg"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -47,24 +50,25 @@ namespace OpenWifi { | ||||
|         SenderThr_.join(); | ||||
|     } | ||||
|  | ||||
|     void SMTPMailerService::reinitialize(Poco::Util::Application &self) { | ||||
|     void SMTPMailerService::reinitialize([[maybe_unused]] Poco::Util::Application &self) { | ||||
|         MicroService::instance().LoadConfigurationFile(); | ||||
|         Logger().information("Reinitializing."); | ||||
|         poco_information(Logger(),"Reinitializing."); | ||||
|         LoadMyConfig(); | ||||
|     } | ||||
|  | ||||
|     bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { | ||||
|     bool SMTPMailerService::SendMessage([[maybe_unused]] const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { | ||||
|         std::lock_guard G(Mutex_); | ||||
|         PendingMessages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr), | ||||
|         PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(), | ||||
|                                             .LastTry=0, | ||||
|                                             .Sent=0, | ||||
|                                             .File=Poco::File(TemplateDir_ + "/" +Name), | ||||
|                                             .TemplateName=Name, | ||||
|                                             .Attrs=Attrs}); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void SMTPMailerService::run() { | ||||
|         Running_ = true; | ||||
|         Utils::SetThreadName("smtp-mailer"); | ||||
|         while(Running_) { | ||||
|  | ||||
|             Poco::Thread::trySleep(10000); | ||||
| @@ -80,17 +84,25 @@ namespace OpenWifi { | ||||
|                 if(!Running_) | ||||
|                     break; | ||||
|                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|                 uint64_t Now = std::time(nullptr); | ||||
|                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { | ||||
|                     if (SendIt(*i)) { | ||||
|                         Logger().information(Poco::format("Attempting to deliver for mail '%s'.", Recipient)); | ||||
|                 uint64_t now = OpenWifi::Now(); | ||||
|                 if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) { | ||||
|                     switch(SendIt(*i)) { | ||||
|                         case MessageSendStatus::msg_sent: { | ||||
|                             poco_information(Logger(),fmt::format("Attempting to deliver for mail '{}'.", Recipient)); | ||||
|                             i = Messages_.erase(i); | ||||
|                     } else { | ||||
|                         i->LastTry = Now; | ||||
|                         } break; | ||||
|                         case MessageSendStatus::msg_not_sent_but_resend: { | ||||
|                             poco_information(Logger(),fmt::format("Mail for '{}' was not. We will retry later.", Recipient)); | ||||
|                             i->LastTry = now; | ||||
|                             ++i; | ||||
|                         } break; | ||||
|                         case MessageSendStatus::msg_not_sent_but_do_not_resend: { | ||||
|                             poco_information(Logger(),fmt::format("Mail for '{}' will not be sent. Check email address", Recipient)); | ||||
|                             i = Messages_.erase(i); | ||||
|                         } break; | ||||
|                     } | ||||
|                 } else if ((Now-i->Posted)>MailAbandon_) { | ||||
|                     Logger().information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient)); | ||||
|                 } else if ((now-i->Posted)>MailAbandon_) { | ||||
|                     poco_information(Logger(),fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient)); | ||||
|                     i = Messages_.erase(i); | ||||
|                 } else { | ||||
|                     ++i; | ||||
| @@ -105,14 +117,12 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||
|     MessageSendStatus SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||
|  | ||||
|         std::string             Recipient; | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             Poco::Net::MailMessage  Message; | ||||
|             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|  | ||||
|             auto H1 = Msg.Attrs.find(SENDER); | ||||
|             std::string TheSender; | ||||
|             if(H1!=Msg.Attrs.end()) { | ||||
| @@ -120,32 +130,40 @@ namespace OpenWifi { | ||||
|             } else { | ||||
|                 TheSender = Sender_ ; | ||||
|             } | ||||
|             Message.setSender( TheSender ); | ||||
|             Logger().information(Poco::format("Sending message to:%s from %s",Recipient,TheSender)); | ||||
|             Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||
|  | ||||
|             auto Message = std::make_unique<Poco::Net::MailMessage>(); | ||||
|  | ||||
|             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|             Message->setSender( TheSender ); | ||||
|             Message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||
|             Message->setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||
|  | ||||
|             poco_information(Logger(),fmt::format("Sending message to:{} from {}",Recipient,TheSender)); | ||||
|  | ||||
|             if(Msg.Attrs.find(TEXT) != Msg.Attrs.end()) { | ||||
|                 std::string Content = Msg.Attrs.find(TEXT)->second; | ||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||
|                 Message->addContent(new Poco::Net::StringPartSource(Content)); | ||||
|             } else { | ||||
|                 std::string Content = Utils::LoadFile(Msg.File); | ||||
|                 for(const auto &format:{"html","txt"}) { | ||||
|                     std::string Content = Utils::LoadFile(TemplateDir_ + Msg.TemplateName + "." + format ); | ||||
|                     Types::StringPairVec Variables; | ||||
|                     FillVariables(Msg.Attrs, Variables); | ||||
|                     Utils::ReplaceVariables(Content, Variables); | ||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||
|                     Message->addContent( | ||||
|                             new Poco::Net::StringPartSource(Content, (strcmp(format,"html") == 0 ? "text/html" : "text/plain") )); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             auto Logo = Msg.Attrs.find(LOGO); | ||||
|             if(Logo!=Msg.Attrs.end()) { | ||||
|                 try { | ||||
|                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); | ||||
|                     Poco::File          LogoFile(EmailLogo_); | ||||
|                     std::ifstream       IF(LogoFile.path()); | ||||
|                     std::ostringstream  OS; | ||||
|                     Poco::StreamCopier::copyStream(IF, OS); | ||||
|                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||
|                     Message->addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||
|                 } catch (...) { | ||||
|                     Logger().warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); | ||||
|                     poco_warning(Logger(),fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName())); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -166,18 +184,23 @@ namespace OpenWifi { | ||||
|                           SenderLoginUserName_, | ||||
|                           SenderLoginPassword_ | ||||
|             ); | ||||
|             session.sendMessage(Message); | ||||
|             session.sendMessage(*Message); | ||||
|             session.close(); | ||||
|             return true; | ||||
|             return MessageSendStatus::msg_sent; | ||||
|         } | ||||
|         catch (const Poco::Net::SMTPException &S) { | ||||
|             Logger().log(S); | ||||
|             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||
|         } | ||||
|         catch (const Poco::Exception& E) | ||||
|         { | ||||
|             Logger().log(E); | ||||
|             return MessageSendStatus::msg_not_sent_but_resend; | ||||
|         } | ||||
|         catch (const std::exception &E) { | ||||
|             Logger().warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what())); | ||||
|             poco_warning(Logger(),fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what())); | ||||
|             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -27,7 +27,8 @@ namespace OpenWifi { | ||||
|         LOGO, | ||||
|         TEXT, | ||||
|         CHALLENGE_CODE, | ||||
|         SENDER | ||||
|         SENDER, | ||||
|         ACTION_LINK_HTML | ||||
|     }; | ||||
|  | ||||
|     static const std::map<MESSAGE_ATTRIBUTES,const std::string> | ||||
| @@ -44,7 +45,8 @@ namespace OpenWifi { | ||||
|                                  {  LOGO, "LOGO"}, | ||||
|                                  {  TEXT, "TEXT"}, | ||||
|                                  {  CHALLENGE_CODE, "CHALLENGE_CODE"}, | ||||
|                                  {  SENDER, "SENDER"} | ||||
|                                  {  SENDER, "SENDER"}, | ||||
|                                  {  ACTION_LINK_HTML, "ACTION_LINK_HTML"}, | ||||
|                                  }; | ||||
|  | ||||
|     inline const std::string & MessageAttributeToVar(MESSAGE_ATTRIBUTES Attr) { | ||||
| @@ -56,6 +58,12 @@ namespace OpenWifi { | ||||
|     } | ||||
|     typedef std::map<MESSAGE_ATTRIBUTES, std::string>   MessageAttributes; | ||||
|  | ||||
|     enum class MessageSendStatus { | ||||
|         msg_sent, | ||||
|         msg_not_sent_but_resend, | ||||
|         msg_not_sent_but_do_not_resend | ||||
|     }; | ||||
|  | ||||
|     class SMTPMailerService : public SubSystemServer, Poco::Runnable { | ||||
|         public: | ||||
|            static SMTPMailerService *instance() { | ||||
| @@ -67,7 +75,7 @@ namespace OpenWifi { | ||||
|                uint64_t             Posted=0; | ||||
|                uint64_t             LastTry=0; | ||||
|                uint64_t             Sent=0; | ||||
|                Poco::File           File; | ||||
|                std::string          TemplateName; | ||||
|                MessageAttributes    Attrs; | ||||
|             }; | ||||
|  | ||||
| @@ -76,7 +84,7 @@ namespace OpenWifi { | ||||
|             void Stop() override; | ||||
|  | ||||
|             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); | ||||
|             bool SendIt(const MessageEvent &Msg); | ||||
|             MessageSendStatus SendIt(const MessageEvent &Msg); | ||||
|             void LoadMyConfig(); | ||||
|             void reinitialize(Poco::Util::Application &self) override; | ||||
|             bool Enabled() const { return Enabled_; } | ||||
| @@ -84,9 +92,9 @@ namespace OpenWifi { | ||||
|         private: | ||||
|             std::string             MailHost_; | ||||
|             std::string             Sender_; | ||||
|             int                     MailHostPort_=25; | ||||
|             int                     MailRetry_=2*60; | ||||
|             int                     MailAbandon_=2*60*20; | ||||
|             uint32_t                MailHostPort_=25; | ||||
|             uint64_t                MailRetry_=2*60; | ||||
|             uint64_t                MailAbandon_=2*60*20; | ||||
|             std::string             SenderLoginUserName_; | ||||
|             std::string             SenderLoginPassword_; | ||||
|             std::string             LoginMethod_ = "login"; | ||||
| @@ -96,6 +104,8 @@ namespace OpenWifi { | ||||
|             Poco::Thread            SenderThr_; | ||||
|             std::atomic_bool        Running_=false; | ||||
|             bool                    Enabled_=false; | ||||
|             bool                    UseHTML_=false; | ||||
|             std::string             EmailLogo_{"logo.jpg"}; | ||||
|  | ||||
|             SMTPMailerService() noexcept: | ||||
|                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") | ||||
|   | ||||
| @@ -22,7 +22,7 @@ namespace OpenWifi { | ||||
|                 U.email = MicroService::instance().ConfigGetString("authentication.default.username", ""); | ||||
|                 U.id = NewDefaultUseridStockUUID; | ||||
|                 U.userRole = SecurityObjects::ROOT; | ||||
|                 U.creationDate = std::time(nullptr); | ||||
|                 U.creationDate = OpenWifi::Now(); | ||||
|                 U.validated = true; | ||||
|                 U.name = "Default User"; | ||||
|                 U.description = "Default user should be deleted."; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     int StorageService::Start() { | ||||
| 		std::lock_guard		Guard(Mutex_); | ||||
|         poco_information(Logger(),"Starting..."); | ||||
|  | ||||
| 		StorageClass::Start(); | ||||
|  | ||||
| @@ -29,7 +30,7 @@ namespace OpenWifi { | ||||
|         PreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("Preferences", "pre", dbType_,*Pool_, Logger()); | ||||
|         SubPreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("SubPreferences", "prs", dbType_,*Pool_, Logger()); | ||||
|         ActionLinksDB_ = std::make_unique<OpenWifi::ActionLinkDB>("Actions", "act", dbType_,*Pool_, Logger()); | ||||
|         AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("Avatars", "ava", dbType_,*Pool_, Logger()); | ||||
|         AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("Avatars2", "ava", dbType_,*Pool_, Logger()); | ||||
|         SubAvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("SubAvatars", "avs", dbType_,*Pool_, Logger()); | ||||
|         LoginDB_ = std::make_unique<OpenWifi::LoginDB>("Logins", "lin", dbType_,*Pool_, Logger()); | ||||
|         SubLoginDB_ = std::make_unique<OpenWifi::LoginDB>("SubLogins", "lis", dbType_,*Pool_, Logger()); | ||||
| @@ -51,18 +52,20 @@ namespace OpenWifi { | ||||
| 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | ||||
| 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | ||||
| 		Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | ||||
| 		Timer_.start(*Archivercallback_); | ||||
| 		Timer_.start(*Archivercallback_, MicroService::instance().TimerPool()); | ||||
|  | ||||
| 		return 0; | ||||
|     } | ||||
|  | ||||
|     void StorageService::Stop() { | ||||
|         Logger().notice("Stopping."); | ||||
|         poco_information(Logger(),"Stopping..."); | ||||
|         Timer_.stop(); | ||||
|         StorageClass::Stop(); | ||||
|         poco_information(Logger(),"Stopped..."); | ||||
|     } | ||||
|  | ||||
|     void Archiver::onTimer(Poco::Timer &timer) { | ||||
|     void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||
|         Utils::SetThreadName("strg-arch"); | ||||
|         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); | ||||
|         logger.information("Squiggy the DB: removing old tokens."); | ||||
|         StorageService()->SubTokenDB().CleanExpiredTokens(); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #define OWSEC_TOTPCACHE_H | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "seclibs/cpptotp/bytes.h" | ||||
| #include "seclibs/qrcode/qrcodegen.hpp" | ||||
| #include "seclibs/cpptotp/otp.h" | ||||
| @@ -41,7 +42,6 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { | ||||
|  | ||||
|             std::string uri{ | ||||
|                 "otpauth://totp/" + Issuer_ + ":" + | ||||
|                 email + "?secret=" + Secret + "&issuer=" + Issuer_ | ||||
| @@ -53,12 +53,12 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             uint64_t Now = OpenWifi::Now(); | ||||
|             uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6); | ||||
|             char buffer[16]; | ||||
|             char buffer[16]{0}; | ||||
|             sprintf(buffer,"%06u",p); | ||||
|             Expecting = buffer; | ||||
|             return Code == buffer; | ||||
|             Expecting = std::string(buffer); | ||||
|             return Code == Expecting; | ||||
|         } | ||||
|  | ||||
|         int Start() override { | ||||
| @@ -76,7 +76,7 @@ namespace OpenWifi { | ||||
|                 if(Reset) { | ||||
|                     std::string Base32Secret; | ||||
|                     Hint->second.Subscriber = Subscriber; | ||||
|                     Hint->second.Start = std::time(nullptr); | ||||
|                     Hint->second.Start = OpenWifi::Now(); | ||||
|                     Hint->second.Done = 0; | ||||
|                     Hint->second.Verifications = 0; | ||||
|                     Hint->second.Secret = GenerateSecret(20,Base32Secret); | ||||
| @@ -93,21 +93,21 @@ namespace OpenWifi { | ||||
|             QRCode = GenerateQRCode(Base32Secret, User.email); | ||||
|  | ||||
|             Entry E{ .Subscriber = Subscriber, | ||||
|                      .Start = (uint64_t )std::time(nullptr), | ||||
|                      .Start = OpenWifi::Now(), | ||||
|                      .Done = 0, | ||||
|                      .Verifications = 0, | ||||
|                      .Secret = Secret, | ||||
|                      .QRCode = QRCode | ||||
|                      .QRCode = QRCode, | ||||
|                      .LastCode = "" | ||||
|                      }; | ||||
|             Cache_[User.id] = E; | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         inline bool ContinueValidation(const SecurityObjects::UserInfo &User, bool Subscriber, const std::string & Code, | ||||
|                                        uint64_t &NextIndex, bool &MoreCodes, uint64_t & ErrorCode, std::string & ErrorText ) { | ||||
|                                        uint64_t &NextIndex, bool &MoreCodes, RESTAPI::Errors::msg & Error ) { | ||||
|             auto Hint = Cache_.find(User.id); | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             ErrorCode = 0; | ||||
|             uint64_t Now = OpenWifi::Now(); | ||||
|             if(Hint!=Cache_.end() && Subscriber==Hint->second.Subscriber && (Now-Hint->second.Start)<(15*60)) { | ||||
|                 std::string Expecting; | ||||
|                 if (NextIndex == 1 && Hint->second.Verifications == 0 && ValidateCode(Hint->second.Secret, Code, Expecting)) { | ||||
| @@ -123,32 +123,27 @@ namespace OpenWifi { | ||||
|                     return true; | ||||
|                 } else { | ||||
|                     if(!ValidateCode(Hint->second.Secret, Code, Expecting)) { | ||||
|                         ErrorCode = 1; | ||||
|                         ErrorText = "Invalid code."; | ||||
|                         Error = RESTAPI::Errors::TOTInvalidCode; | ||||
|                         return false; | ||||
|                     } else if(NextIndex!=1 && NextIndex != 2) { | ||||
|                         ErrorCode = 2; | ||||
|                         ErrorText = "Invalid Index"; | ||||
|                         Error = RESTAPI::Errors::TOTInvalidIndex; | ||||
|                         return false; | ||||
|                     } else if(Code == Hint->second.LastCode) { | ||||
|                         ErrorCode = 3; | ||||
|                         ErrorText = "Code is repeated. Must be new code."; | ||||
|                         Error = RESTAPI::Errors::TOTRepeatedCode; | ||||
|                         return false; | ||||
|                     } | ||||
|                     ErrorCode = 5; | ||||
|                     ErrorText = "Invalid protocol sequence."; | ||||
|                     Error = RESTAPI::Errors::TOTInvalidProtocol; | ||||
|                     return false; | ||||
|                 } | ||||
|             } else { | ||||
|                 ErrorCode = 4; | ||||
|                 ErrorText = "No validation session present."; | ||||
|                 Error = RESTAPI::Errors::TOTNoSession; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         inline bool CompleteValidation(const SecurityObjects::UserInfo &User, bool Subscriber, std::string & Secret) { | ||||
|             auto Hint = Cache_.find(User.id); | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             uint64_t Now = OpenWifi::Now(); | ||||
|             if(Hint!=Cache_.end() && Subscriber==Hint->second.Subscriber && (Now-Hint->second.Start)<(15*60) && Hint->second.Done!=0) { | ||||
|                 Secret = Hint->second.Secret; | ||||
|                 Cache_.erase(Hint); | ||||
|   | ||||
| @@ -13,9 +13,11 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||
| static const std::string GitUCentralJSONSchemaFile{ | ||||
| 	"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||
|  | ||||
| static json DefaultUCentralSchema = R"( | ||||
|  | ||||
|     static json DefaultUCentralSchema = R"( | ||||
| { | ||||
| 	"$id": "https://openwrt.org/ucentral.schema.json", | ||||
| 	"$schema": "http://json-schema.org/draft-07/schema#", | ||||
| @@ -42,7 +44,7 @@ namespace OpenWifi { | ||||
| 		"switch": { | ||||
| 			"$ref": "#/$defs/switch" | ||||
| 		}, | ||||
|         "radios": { | ||||
| 		"radiosgrep": { | ||||
| 			"type": "array", | ||||
| 			"items": { | ||||
| 				"$ref": "#/$defs/radio" | ||||
| @@ -75,6 +77,10 @@ namespace OpenWifi { | ||||
| 				"name": { | ||||
| 					"type": "string" | ||||
| 				}, | ||||
| 				"hostname": { | ||||
| 					"type": "string", | ||||
| 					"format": "hostname" | ||||
| 				}, | ||||
| 				"location": { | ||||
| 					"type": "string" | ||||
| 				}, | ||||
| @@ -101,12 +107,14 @@ namespace OpenWifi { | ||||
| 			"items": { | ||||
| 				"type": "string", | ||||
| 				"enum": [ | ||||
| 					"CS0", | ||||
| 					"CS1", | ||||
| 					"CS2", | ||||
| 					"CS3", | ||||
| 					"CS4", | ||||
| 					"CS5", | ||||
| 					"CS6", | ||||
| 					"CS7", | ||||
| 					"AF11", | ||||
| 					"AF12", | ||||
| 					"AF13", | ||||
| @@ -120,12 +128,15 @@ namespace OpenWifi { | ||||
| 					"AF42", | ||||
| 					"AF43", | ||||
| 					"DF", | ||||
|                     "EF" | ||||
| 					"EF", | ||||
| 					"VA", | ||||
| 					"LE" | ||||
| 				] | ||||
| 			} | ||||
| 		}, | ||||
|         "globals.wireless-multimedia": { | ||||
| 		"globals.wireless-multimedia.table": { | ||||
| 			"type": "object", | ||||
| 			"additionalProperties": false, | ||||
| 			"properties": { | ||||
| 				"UP0": { | ||||
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector" | ||||
| @@ -153,11 +164,19 @@ namespace OpenWifi { | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
|         "globals.wireless-multimedia-profile": { | ||||
| 		"globals.wireless-multimedia.profile": { | ||||
| 			"type": "object", | ||||
| 			"additionalProperties": false, | ||||
| 			"properties": { | ||||
| 				"profile": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
|                 "enterprise" | ||||
| 						"enterprise", | ||||
| 						"rfc8325", | ||||
| 						"3gpp" | ||||
| 					] | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		"globals": { | ||||
| 			"type": "object", | ||||
| @@ -177,12 +196,11 @@ namespace OpenWifi { | ||||
| 					] | ||||
| 				}, | ||||
| 				"wireless-multimedia": { | ||||
|                     "oneOf": [ | ||||
|                         { | ||||
|                             "$ref": "#/$defs/globals.wireless-multimedia" | ||||
| 					"anyOf": [{ | ||||
| 							"$ref": "#/$defs/globals.wireless-multimedia.table" | ||||
| 						}, | ||||
| 						{ | ||||
|                             "$ref": "#/$defs/globals.wireless-multimedia-profile" | ||||
| 							"$ref": "#/$defs/globals.wireless-multimedia.profile" | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| @@ -372,10 +390,9 @@ namespace OpenWifi { | ||||
| 					] | ||||
| 				}, | ||||
| 				"channel": { | ||||
|                     "oneOf": [ | ||||
|                         { | ||||
| 					"oneOf": [{ | ||||
| 							"type": "integer", | ||||
|                             "maximum": 171, | ||||
| 							"maximum": 196, | ||||
| 							"minimum": 1 | ||||
| 						}, | ||||
| 						{ | ||||
| @@ -384,6 +401,14 @@ namespace OpenWifi { | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"valid-channels": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"type": "integer", | ||||
| 						"maximum": 196, | ||||
| 						"minimum": 1 | ||||
| 					} | ||||
| 				}, | ||||
| 				"country": { | ||||
| 					"type": "string", | ||||
| 					"maxLength": 2, | ||||
| @@ -392,6 +417,10 @@ namespace OpenWifi { | ||||
| 						"US" | ||||
| 					] | ||||
| 				}, | ||||
| 				"allow-dfs": { | ||||
| 					"type": "boolean", | ||||
| 					"default": true | ||||
| 				}, | ||||
| 				"channel-mode": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| @@ -490,17 +519,17 @@ namespace OpenWifi { | ||||
| 					"maximum": 4050 | ||||
| 				}, | ||||
| 				"proto": { | ||||
|     "decription": "The L2 vlan tag that shall be added (1q,1ad) ", | ||||
| 					"decription": "The L2 vlan tag that shall be added (1q,1ad ) ", | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| 						"802.1ad", | ||||
| 						"802.1q" | ||||
| 					], | ||||
| 					"default": "802.1q" | ||||
| } | ||||
| } | ||||
| }, | ||||
| "interface.bridge": { | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		"interface.bridge": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"mtu": { | ||||
| @@ -641,6 +670,47 @@ namespace OpenWifi { | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		"interface.ipv4.port-forward": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| 						"tcp", | ||||
| 						"udp", | ||||
| 						"any" | ||||
| 					], | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"external-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				}, | ||||
| 				"internal-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv4", | ||||
| 					"example": "0.0.0.120" | ||||
| 				}, | ||||
| 				"internal-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"external-port", | ||||
| 				"internal-address" | ||||
| 			] | ||||
| 		}, | ||||
| 		"interface.ipv4": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| @@ -694,6 +764,12 @@ namespace OpenWifi { | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv4.dhcp-lease" | ||||
| 					} | ||||
| 				}, | ||||
| 				"port-forward": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv4.port-forward" | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @@ -723,6 +799,96 @@ namespace OpenWifi { | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		"interface.ipv6.port-forward": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| 						"tcp", | ||||
| 						"udp", | ||||
| 						"any" | ||||
| 					], | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"external-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				}, | ||||
| 				"internal-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv6", | ||||
| 					"example": "::1234:abcd" | ||||
| 				}, | ||||
| 				"internal-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"external-port", | ||||
| 				"internal-address" | ||||
| 			] | ||||
| 		}, | ||||
| 		"interface.ipv6.traffic-allow": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"source-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "uc-cidr6", | ||||
| 					"example": "2001:db8:1234:abcd::/64", | ||||
| 					"default": "::/0" | ||||
| 				}, | ||||
| 				"source-ports": { | ||||
| 					"type": "array", | ||||
| 					"minItems": 1, | ||||
| 					"items": { | ||||
| 						"type": [ | ||||
| 							"integer", | ||||
| 							"string" | ||||
| 						], | ||||
| 						"minimum": 0, | ||||
| 						"maximum": 65535, | ||||
| 						"format": "uc-portrange" | ||||
| 					} | ||||
| 				}, | ||||
| 				"destination-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv6", | ||||
| 					"example": "::1000" | ||||
| 				}, | ||||
| 				"destination-ports": { | ||||
| 					"type": "array", | ||||
| 					"minItems": 1, | ||||
| 					"items": { | ||||
| 						"type": [ | ||||
| 							"integer", | ||||
| 							"string" | ||||
| 						], | ||||
| 						"minimum": 0, | ||||
| 						"maximum": 65535, | ||||
| 						"format": "uc-portrange" | ||||
| 					} | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"destination-address" | ||||
| 			] | ||||
| 		}, | ||||
| 		"interface.ipv6": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| @@ -754,6 +920,18 @@ namespace OpenWifi { | ||||
| 				}, | ||||
| 				"dhcpv6": { | ||||
| 					"$ref": "#/$defs/interface.ipv6.dhcpv6" | ||||
| 				}, | ||||
| 				"port-forward": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv6.port-forward" | ||||
| 					} | ||||
| 				}, | ||||
| 				"traffic-allow": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv6.traffic-allow" | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @@ -821,8 +999,7 @@ namespace OpenWifi { | ||||
| 			} | ||||
| 		}, | ||||
| 		"interface.broad-band": { | ||||
|     "oneOf": [ | ||||
|             { | ||||
| 			"oneOf": [{ | ||||
| 					"$ref": "#/$defs/interface.broad-band.wwan" | ||||
| 				}, | ||||
| 				{ | ||||
| @@ -839,7 +1016,7 @@ namespace OpenWifi { | ||||
| 				}, | ||||
| 				"gateway-fqdn": { | ||||
| 					"type": "string", | ||||
|             "format": "fqdn", | ||||
| 					"format": "uc-fqdn", | ||||
| 					"default": "ucentral.splash" | ||||
| 				}, | ||||
| 				"max-clients": { | ||||
| @@ -874,6 +1051,7 @@ namespace OpenWifi { | ||||
| 						"psk", | ||||
| 						"psk2", | ||||
| 						"psk-mixed", | ||||
| 						"psk2-radius", | ||||
| 						"wpa", | ||||
| 						"wpa2", | ||||
| 						"wpa-mixed", | ||||
| @@ -934,6 +1112,10 @@ namespace OpenWifi { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
| 				}, | ||||
| 				"reduced-neighbor-reporting": { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
| 				}, | ||||
| 				"lci": { | ||||
| 					"type": "string" | ||||
| 				}, | ||||
| @@ -1074,8 +1256,7 @@ namespace OpenWifi { | ||||
| 								"minimum": 1 | ||||
| 							}, | ||||
| 							"value": { | ||||
|                         "anyOf": [ | ||||
|                                 { | ||||
| 								"anyOf": [{ | ||||
| 										"type": "integer", | ||||
| 										"maximum": 4294967295, | ||||
| 										"minimum": 0 | ||||
| @@ -1086,8 +1267,7 @@ namespace OpenWifi { | ||||
| 								] | ||||
| 							} | ||||
| 						}, | ||||
|                     "examples": [ | ||||
|                             { | ||||
| 						"examples": [{ | ||||
| 								"id": 27, | ||||
| 								"value": 900 | ||||
| 							}, | ||||
| @@ -1124,12 +1304,49 @@ namespace OpenWifi { | ||||
| 				"local": { | ||||
| 					"$ref": "#/$defs/interface.ssid.radius.local" | ||||
| 				}, | ||||
| 				"dynamic-authorization": { | ||||
| 					"type": "object", | ||||
| 					"properties": { | ||||
| 						"host": { | ||||
| 							"type": "string", | ||||
| 							"format": "uc-ip", | ||||
| 							"examples": [ | ||||
| 								"192.168.1.10" | ||||
| 							] | ||||
| 						}, | ||||
| 						"port": { | ||||
| 							"type": "integer", | ||||
| 							"maximum": 65535, | ||||
| 							"minimum": 1024, | ||||
| 							"examples": [ | ||||
| 								1812 | ||||
| 							] | ||||
| 						}, | ||||
| 						"secret": { | ||||
| 							"type": "string", | ||||
| 							"examples": [ | ||||
| 								"secret" | ||||
| 							] | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
| 				"authentication": { | ||||
| 					"allOf": [{ | ||||
| 							"$ref": "#/$defs/interface.ssid.radius.server" | ||||
| 						}, | ||||
|             "accounting": { | ||||
|             "allOf": [ | ||||
| 						{ | ||||
| 							"type": "object", | ||||
| 							"properties": { | ||||
| 								"mac-filter": { | ||||
| 									"type": "boolean", | ||||
| 									"default": false | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				"accounting": { | ||||
| 					"allOf": [{ | ||||
| 							"$ref": "#/$defs/interface.ssid.radius.server" | ||||
| 						}, | ||||
| 						{ | ||||
| @@ -1332,15 +1549,13 @@ namespace OpenWifi { | ||||
| 								] | ||||
| 							} | ||||
| 						}, | ||||
|                     "examples": [ | ||||
|                             { | ||||
| 						"examples": [{ | ||||
| 							"width": 32, | ||||
| 							"height": 32, | ||||
| 							"type": "image/png", | ||||
| 							"language": "eng", | ||||
| 							"icon": "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" | ||||
|                             } | ||||
|                             ] | ||||
| 						}] | ||||
| 					} | ||||
| 				}, | ||||
| 				"wan-metrics": { | ||||
| @@ -1467,6 +1682,11 @@ namespace OpenWifi { | ||||
| 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | ||||
| 					"type": "string" | ||||
| 				}, | ||||
| 				"fils-discovery-interval": { | ||||
| 					"type": "integer", | ||||
| 					"default": 20, | ||||
| 					"maximum": 10000 | ||||
| 				}, | ||||
| 				"encryption": { | ||||
| 					"$ref": "#/$defs/interface.ssid.encryption" | ||||
| 				}, | ||||
| @@ -1581,8 +1801,7 @@ namespace OpenWifi { | ||||
| 			} | ||||
| 		}, | ||||
| 		"interface.tunnel": { | ||||
|     "oneOf": [ | ||||
|             { | ||||
| 			"oneOf": [{ | ||||
| 					"$ref": "#/$defs/interface.tunnel.mesh" | ||||
| 				}, | ||||
| 				{ | ||||
| @@ -1788,6 +2007,11 @@ namespace OpenWifi { | ||||
| 					"type": "integer", | ||||
| 					"minimum": 32, | ||||
| 					"default": 1000 | ||||
| 				}, | ||||
| 				"priority": { | ||||
| 					"type": "integer", | ||||
| 					"minimum": 0, | ||||
| 					"default": 7 | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @@ -1934,7 +2158,7 @@ namespace OpenWifi { | ||||
| 			"properties": { | ||||
| 				"controller": { | ||||
| 					"type": "string", | ||||
|             "format": "ip", | ||||
| 					"format": "uc-ip", | ||||
| 					"example": "192.168.10.1" | ||||
| 				}, | ||||
| 				"datapath-description": { | ||||
| @@ -1951,6 +2175,11 @@ namespace OpenWifi { | ||||
| 					], | ||||
| 					"default": "ssl" | ||||
| 				}, | ||||
| 				"port": { | ||||
| 					"type": "integer", | ||||
| 					"maximum": 65535, | ||||
| 					"default": 6653 | ||||
| 				}, | ||||
| 				"ca-certificate": { | ||||
| 					"type": "string" | ||||
| 				}, | ||||
| @@ -2018,9 +2247,42 @@ namespace OpenWifi { | ||||
| 				"auto-channel": { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
| 				}, | ||||
| 				"ipv6": { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		"service.quality-of-service.class-selector": { | ||||
| 			"type": "string", | ||||
| 			"enum": [ | ||||
| 				"CS0", | ||||
| 				"CS1", | ||||
| 				"CS2", | ||||
| 				"CS3", | ||||
| 				"CS4", | ||||
| 				"CS5", | ||||
| 				"CS6", | ||||
| 				"CS7", | ||||
| 				"AF11", | ||||
| 				"AF12", | ||||
| 				"AF13", | ||||
| 				"AF21", | ||||
| 				"AF22", | ||||
| 				"AF23", | ||||
| 				"AF31", | ||||
| 				"AF32", | ||||
| 				"AF33", | ||||
| 				"AF41", | ||||
| 				"AF42", | ||||
| 				"AF43", | ||||
| 				"DF", | ||||
| 				"EF", | ||||
| 				"VA", | ||||
| 				"LE" | ||||
| 			] | ||||
| 		}, | ||||
| 		"service.quality-of-service": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| @@ -2039,23 +2301,26 @@ namespace OpenWifi { | ||||
| 					"type": "integer", | ||||
| 					"default": 0 | ||||
| 				}, | ||||
| 				"bulk-detection": { | ||||
| 					"type": "object", | ||||
| 					"properties": { | ||||
| 						"dscp": { | ||||
| 							"$ref": "#/$defs/service.quality-of-service.class-selector", | ||||
| 							"default": "CS0" | ||||
| 						}, | ||||
| 						"packets-per-second": { | ||||
| 							"type": "number", | ||||
| 							"default": 0 | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
| 				"classifier": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"type": "object", | ||||
| 						"properties": { | ||||
| 							"dscp": { | ||||
|                         "type": "string", | ||||
|                         "enum": [ | ||||
|                                 "CS0", | ||||
|                                 "CS1", | ||||
|                                 "CS2", | ||||
|                                 "CS3", | ||||
|                                 "CS4", | ||||
|                                 "CS5", | ||||
|                                 "CS6", | ||||
|                                 "CS7" | ||||
|                                 ], | ||||
| 								"$ref": "#/$defs/service.quality-of-service.class-selector", | ||||
| 								"default": "CS1" | ||||
| 							}, | ||||
| 							"ports": { | ||||
| @@ -2083,12 +2348,25 @@ namespace OpenWifi { | ||||
| 											"default": true | ||||
| 										} | ||||
| 									} | ||||
| 								} | ||||
| 							}, | ||||
| 							"dns": { | ||||
| 								"type": "array", | ||||
| 								"items": { | ||||
| 									"type": "object", | ||||
| 									"properties": { | ||||
| 										"fqdn": { | ||||
| 											"type": "string", | ||||
|                                 "format": "fqdn" | ||||
| 											"format": "uc-fqdn" | ||||
| 										}, | ||||
| 										"suffix-matching": { | ||||
| 											"type": "boolean", | ||||
| 											"default": true | ||||
| 										}, | ||||
| 										"reclassify": { | ||||
| 											"type": "boolean", | ||||
| 											"default": true | ||||
| 										} | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| @@ -2111,21 +2389,36 @@ namespace OpenWifi { | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
|     "service.airtime-policies": { | ||||
| 		"service.airtime-fairness": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
|         "dns-match": { | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|                 "type": "string", | ||||
|                 "examples": [ | ||||
|                         "*.voice.example.com" | ||||
|                         ] | ||||
|             } | ||||
| 				"voice-weight": { | ||||
| 					"type": "number", | ||||
| 					"default": 4 | ||||
| 				}, | ||||
|             "dns-weight": { | ||||
|             "type": "integer", | ||||
| 				"packet-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 100 | ||||
| 				}, | ||||
| 				"bulk-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 50 | ||||
| 				}, | ||||
| 				"priority-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 30 | ||||
| 				}, | ||||
| 				"weight-normal": { | ||||
| 					"type": "number", | ||||
| 					"default": 256 | ||||
| 				}, | ||||
| 				"weight-priority": { | ||||
| 					"type": "number", | ||||
| 					"default": 394 | ||||
| 				}, | ||||
| 				"weight-bulk": { | ||||
| 					"type": "number", | ||||
| 					"default": 128 | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @@ -2180,8 +2473,8 @@ namespace OpenWifi { | ||||
| 				"facebook-wifi": { | ||||
| 					"$ref": "#/$defs/service.facebook-wifi" | ||||
| 				}, | ||||
|             "airtime-policies": { | ||||
|             "$ref": "#/$defs/service.airtime-policies" | ||||
| 				"airtime-fairness": { | ||||
| 					"$ref": "#/$defs/service.airtime-fairness" | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @@ -2312,21 +2605,37 @@ namespace OpenWifi { | ||||
| 					] | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| } | ||||
| } | ||||
|     )"_json; | ||||
| )"_json; | ||||
|  | ||||
|     class ConfigurationValidator *ConfigurationValidator::instance_ = nullptr; | ||||
|     class custom_error_handler : public nlohmann::json_schema::basic_error_handler | ||||
|     { | ||||
|         void error(const nlohmann::json_pointer<nlohmann::basic_json<>> &pointer, const json &instance, | ||||
|                    const std::string &message) override | ||||
|         { | ||||
|             nlohmann::json_schema::basic_error_handler::error(pointer, instance, message); | ||||
|             std::cout << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n"; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     void ConfigurationValidator::Init() { | ||||
|         if(Initialized_) | ||||
|             return; | ||||
|  | ||||
|         std::string GitSchema; | ||||
| 		if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) { | ||||
| 			RootSchema_ = DefaultUCentralSchema; | ||||
| 			Logger().information("Using uCentral validation from built-in default."); | ||||
| 			Initialized_ = Working_ = true; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         try { | ||||
|             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { | ||||
|                 auto schema = json::parse(GitSchema); | ||||
|                 Validator_->set_root_schema(schema); | ||||
| 			auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile); | ||||
|             if(Utils::wgets(GitURI, GitSchema)) { | ||||
|                 RootSchema_ = json::parse(GitSchema); | ||||
|                 Logger().information("Using uCentral validation schema from GIT."); | ||||
|             } else { | ||||
|                 std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" }; | ||||
| @@ -2334,12 +2643,11 @@ namespace OpenWifi { | ||||
|                 std::stringstream   schema_file; | ||||
|                 schema_file << input.rdbuf(); | ||||
|                 input.close(); | ||||
|                 auto schema = json::parse(schema_file.str()); | ||||
|                 Validator_->set_root_schema(schema); | ||||
|                 RootSchema_ = json::parse(schema_file.str()); | ||||
|                 Logger().information("Using uCentral validation schema from local file."); | ||||
|             } | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             Validator_->set_root_schema(DefaultUCentralSchema); | ||||
|             RootSchema_ = DefaultUCentralSchema; | ||||
|             Logger().information("Using uCentral validation from built-in default."); | ||||
|         } | ||||
|         Initialized_ = Working_ = true; | ||||
| @@ -2392,6 +2700,17 @@ namespace OpenWifi { | ||||
|         return IsCIDRv4(value) || IsCIDRv6(value); | ||||
|     } | ||||
|  | ||||
|     static inline bool IsPortRangeIsValid(const std::string &r) { | ||||
|         const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM); | ||||
|  | ||||
|         for(const auto &port:ports) { | ||||
|             uint32_t port_num = std::stoul(port); | ||||
|             if(port_num==0 || port_num>65535) | ||||
|                 return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) | ||||
|     { | ||||
|         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; | ||||
| @@ -2414,7 +2733,7 @@ namespace OpenWifi { | ||||
|         } else if(format == "uc-mac") { | ||||
|             if(std::regex_match(value,mac_regex)) | ||||
|                 return; | ||||
|             throw std::invalid_argument(value + " is not a valid MAC: should be something like 2e60:3500::/64."); | ||||
|             throw std::invalid_argument(value + " is not a valid MAC: should be something like 11:22:33:44:55:66"); | ||||
|         } else if(format == "uc-timeout") { | ||||
|             if(std::regex_match(value,uc_timeout_regex)) | ||||
|                 return; | ||||
| @@ -2442,16 +2761,20 @@ namespace OpenWifi { | ||||
|             } catch (...) { | ||||
|             } | ||||
|             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); | ||||
|         } else if(format == "uc-portrange") { | ||||
|             try { | ||||
|                 if(IsPortRangeIsValid(value)) | ||||
|                     return; | ||||
|                 throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||
|             } catch (...) { | ||||
|             } | ||||
|             throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||
|         } else if(format == "ip") { | ||||
|             if (IsIP(value)) | ||||
|                 return; | ||||
|             throw std::invalid_argument(value + " is not a valid IP address."); | ||||
|         } else { | ||||
|             try { | ||||
|             nlohmann::json_schema::default_string_format_check(format,value); | ||||
|             } catch (const std::logic_error &E) { | ||||
|                 std::string Error{"JSON Schema validation: "}; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -2459,18 +2782,31 @@ namespace OpenWifi { | ||||
|         if(Working_) { | ||||
|             try { | ||||
|                 auto Doc = json::parse(C); | ||||
|                 Validator_->validate(Doc); | ||||
|                 custom_error_handler CE; | ||||
|                 json_validator  Validator(nullptr, my_format_checker); | ||||
|                 Validator.set_root_schema(RootSchema_); | ||||
|                 Validator.validate(Doc,CE); | ||||
|                 return true; | ||||
|             } catch (const std::invalid_argument &E) { | ||||
|                 std::cout << "1 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 Error = E.what(); | ||||
|                 return false; | ||||
|             } catch (const std::logic_error &E) { | ||||
|                 std::cout << "2 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 Error = E.what(); | ||||
|                 return false; | ||||
|             } catch(const std::exception &E) { | ||||
|                 Error = E.what(); | ||||
|                 std::cout << "Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 std::cout << "3 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 return false; | ||||
|             } catch(...) { | ||||
|                 std::cout << "4 Some kind of bullshit exception..." << std::endl; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationValidator::reinitialize(Poco::Util::Application &self) { | ||||
|     void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) { | ||||
|         Logger().information("Reinitializing."); | ||||
|         Working_ = Initialized_ = false; | ||||
|         Init(); | ||||
|   | ||||
| @@ -14,9 +14,8 @@ namespace OpenWifi { | ||||
|     class ConfigurationValidator : public  SubSystemServer { | ||||
|     public: | ||||
|  | ||||
|         static ConfigurationValidator *instance() { | ||||
|             if(instance_== nullptr) | ||||
|                 instance_ = new ConfigurationValidator; | ||||
|         static auto instance() { | ||||
|             static auto instance_ = new ConfigurationValidator; | ||||
|             return instance_; | ||||
|         } | ||||
|  | ||||
| @@ -27,18 +26,17 @@ namespace OpenWifi { | ||||
|         void reinitialize(Poco::Util::Application &self) override; | ||||
|  | ||||
|     private: | ||||
|         static  ConfigurationValidator * instance_; | ||||
|         bool            Initialized_=false; | ||||
|         bool            Working_=false; | ||||
|         void            Init(); | ||||
|         std::unique_ptr<json_validator>  Validator_=std::make_unique<json_validator>(nullptr, my_format_checker); | ||||
|         nlohmann::json  RootSchema_; | ||||
|  | ||||
|         ConfigurationValidator(): | ||||
|             SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); } | ||||
|     inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); } | ||||
|     inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ namespace OpenWifi::KafkaTopics { | ||||
| 	static const std::string SERVICE_EVENTS{"service_events"}; | ||||
| 	static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; | ||||
| 	static const std::string DEVICE_TELEMETRY{"device_telemetry"}; | ||||
|     static const std::string PROVISIONING_CHANGE{"provisioning_change"}; | ||||
|  | ||||
| 	namespace ServiceEvents { | ||||
| 		static const std::string EVENT_JOIN{"join"}; | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										169
									
								
								src/framework/MicroServiceErrorHandler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/framework/MicroServiceErrorHandler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-09-29. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "fmt/format.h" | ||||
| #include "Poco/Util/Application.h" | ||||
| #include "Poco/ErrorHandler.h" | ||||
| #include "Poco/Net/NetException.h" | ||||
| #include "Poco/Net/SSLException.h" | ||||
| #include "Poco/JSON/Template.h" | ||||
| #include "Poco/Thread.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| 	class MicroServiceErrorHandler : public Poco::ErrorHandler { | ||||
| 	  public: | ||||
| 		explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) { | ||||
| 		} | ||||
|  | ||||
| 		inline void exception(const Poco::Exception & Base) override { | ||||
| 			try { | ||||
| 				if(Poco::Thread::current()!= nullptr) { | ||||
| 					t_name = Poco::Thread::current()->getName(); | ||||
| 					t_id = Poco::Thread::current()->id(); | ||||
| 				} else { | ||||
| 					t_name = "startup_code"; | ||||
| 					t_id = 0; | ||||
| 				} | ||||
|  | ||||
| 				App_.logger().log(Base); | ||||
| 				Base.rethrow(); | ||||
|  | ||||
| 			} catch (const Poco::Net::InvalidCertificateException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::InvalidSocketException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::WebSocketException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::ConnectionResetException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::CertificateValidationException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::SSLContextException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Net::SSLException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
|  | ||||
| 			} catch (const Poco::Net::InvalidAddressException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
|  | ||||
| 			} catch (const Poco::Net::NetException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
|  | ||||
| 			} catch (const Poco::IOException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::IOException 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) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::JSON::JSONTemplateException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::JSON::JSONException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::ApplicationException &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (const Poco::Exception &E) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||
| 													  t_name, t_id, E.code(), | ||||
| 													  E.displayText(), | ||||
| 													  E.message(), | ||||
| 													  E.what())); | ||||
| 			} catch (...) { | ||||
| 				poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		inline void exception(const std::exception & E) override { | ||||
| 			if(Poco::Thread::current()!= nullptr) { | ||||
| 				t_name = Poco::Thread::current()->getName(); | ||||
| 				t_id = Poco::Thread::current()->id(); | ||||
| 			} else { | ||||
| 				t_name = "startup_code"; | ||||
| 				t_id = 0; | ||||
| 			} | ||||
| 			poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}", | ||||
| 													t_name,E.what(), | ||||
| 													t_id)); | ||||
| 		} | ||||
|  | ||||
| 		inline void exception() override { | ||||
| 			if(Poco::Thread::current()!= nullptr) { | ||||
| 				t_name = Poco::Thread::current()->getName(); | ||||
| 				t_id = Poco::Thread::current()->id(); | ||||
| 			} else { | ||||
| 				t_name = "startup_code"; | ||||
| 				t_id = 0; | ||||
| 			} | ||||
| 			poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}", | ||||
| 													t_name, t_id)); | ||||
| 		} | ||||
| 	  private: | ||||
| 		Poco::Util::Application	&App_; | ||||
| 		std::string		t_name; | ||||
| 		int 			t_id=0; | ||||
| 	}; | ||||
|  | ||||
| } | ||||
							
								
								
									
										299
									
								
								src/framework/RESTAPI_GWobjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								src/framework/RESTAPI_GWobjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| // | ||||
| //	License type: BSD 3-Clause License | ||||
| //	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
| // | ||||
| //	Created by Stephane Bourque on 2021-03-04. | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include "Poco/JSON/Parser.h" | ||||
| #include "Poco/JSON/Stringifier.h" | ||||
|  | ||||
| #include "Daemon.h" | ||||
| #ifdef	TIP_GATEWAY_SERVICE | ||||
| #include "DeviceRegistry.h" | ||||
| #include "CapabilitiesCache.h" | ||||
| #endif | ||||
|  | ||||
| #include "RESTAPI_GWobjects.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
| using OpenWifi::RESTAPI_utils::EmbedDocument; | ||||
|  | ||||
| namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); | ||||
| #endif | ||||
| 		field_to_json(Obj,"macAddress", MACAddress); | ||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		EmbedDocument("configuration", Obj, Configuration); | ||||
| 		field_to_json(Obj,"notes", Notes); | ||||
| 		field_to_json(Obj,"createdTimestamp", CreationTimestamp); | ||||
| 		field_to_json(Obj,"lastConfigurationChange", LastConfigurationChange); | ||||
| 		field_to_json(Obj,"lastConfigurationDownload", LastConfigurationDownload); | ||||
| 		field_to_json(Obj,"lastFWUpdate", LastFWUpdate); | ||||
| 		field_to_json(Obj,"owner", Owner); | ||||
| 		field_to_json(Obj,"location", Location); | ||||
| 		field_to_json(Obj,"venue", Venue); | ||||
| 		field_to_json(Obj,"firmware", Firmware); | ||||
| 		field_to_json(Obj,"compatible", Compatible); | ||||
| 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | ||||
| 		field_to_json(Obj,"devicePassword", DevicePassword); | ||||
| 		field_to_json(Obj,"subscriber", subscriber); | ||||
| 		field_to_json(Obj,"entity", entity); | ||||
| 		field_to_json(Obj,"modified", modified); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
| 	} | ||||
|  | ||||
| 	void Device::to_json_with_status(Poco::JSON::Object &Obj) const { | ||||
| 		to_json(Obj); | ||||
|  | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		ConnectionState ConState; | ||||
|  | ||||
| 		if (DeviceRegistry()->GetState(SerialNumber, ConState)) { | ||||
| 			ConState.to_json(Obj); | ||||
| 		} else { | ||||
| 			field_to_json(Obj,"ipAddress", ""); | ||||
| 			field_to_json(Obj,"txBytes", (uint64_t) 0); | ||||
| 			field_to_json(Obj,"rxBytes", (uint64_t )0); | ||||
| 			field_to_json(Obj,"messageCount", (uint64_t )0); | ||||
| 			field_to_json(Obj,"connected", false); | ||||
| 			field_to_json(Obj,"lastContact", ""); | ||||
| 			field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); | ||||
| 			field_to_json(Obj,"associations_2G", (uint64_t) 0); | ||||
| 			field_to_json(Obj,"associations_5G", (uint64_t) 0); | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||
| 			field_from_json(Obj,"deviceType",DeviceType); | ||||
| 			field_from_json(Obj,"macAddress",MACAddress); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| 			field_from_json(Obj,"notes",Notes); | ||||
| 			field_from_json(Obj,"manufacturer",Manufacturer); | ||||
| 			field_from_json(Obj,"owner",Owner); | ||||
| 			field_from_json(Obj,"location",Location); | ||||
| 			field_from_json(Obj,"venue",Venue); | ||||
| 			field_from_json(Obj,"compatible",Compatible); | ||||
| 			field_from_json(Obj,"subscriber", subscriber); | ||||
| 			field_from_json(Obj,"entity", entity); | ||||
| 			field_from_json(Obj,"locale", locale); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void Device::Print() const { | ||||
| 		std::cout << "Device: " << SerialNumber << " DeviceType:" << DeviceType << " MACAddress:" << MACAddress << " Manufacturer:" | ||||
| 				  << Manufacturer << " " << Configuration << std::endl; | ||||
| 	} | ||||
|  | ||||
| 	void Statistics::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("data", Obj, Data); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 	} | ||||
|  | ||||
| 	void Capabilities::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("capabilities", Obj, Capabilities); | ||||
| 		field_to_json(Obj,"firstUpdate", FirstUpdate); | ||||
| 		field_to_json(Obj,"lastUpdate", LastUpdate); | ||||
| 	} | ||||
|  | ||||
| 	void DeviceLog::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("data", Obj, Data); | ||||
| 		field_to_json(Obj,"log", Log); | ||||
| 		field_to_json(Obj,"severity", Severity); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 		field_to_json(Obj,"logType", LogType); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 	} | ||||
|  | ||||
| 	void HealthCheck::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("values", Obj, Data); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"sanity", Sanity); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 	} | ||||
|  | ||||
| 	void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("configuration", Obj, Configuration); | ||||
| 		field_to_json(Obj,"name", Name); | ||||
| 		field_to_json(Obj,"modelIds", Models); | ||||
| 		field_to_json(Obj,"description", Description); | ||||
| 		field_to_json(Obj,"created", Created); | ||||
| 		field_to_json(Obj,"lastModified", LastModified); | ||||
| 	} | ||||
|  | ||||
| 	void CommandDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("details", Obj, Details); | ||||
| 		EmbedDocument("results", Obj, Results); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| 		field_to_json(Obj,"command", Command); | ||||
| 		field_to_json(Obj,"errorText", ErrorText); | ||||
| 		field_to_json(Obj,"submittedBy", SubmittedBy); | ||||
| 		field_to_json(Obj,"status", Status); | ||||
| 		field_to_json(Obj,"submitted", Submitted); | ||||
| 		field_to_json(Obj,"executed", Executed); | ||||
| 		field_to_json(Obj,"completed", Completed); | ||||
| 		field_to_json(Obj,"when", RunAt); | ||||
| 		field_to_json(Obj,"errorCode", ErrorCode); | ||||
| 		field_to_json(Obj,"custom", Custom); | ||||
| 		field_to_json(Obj,"waitingForFile", WaitingForFile); | ||||
| 		field_to_json(Obj,"attachFile", AttachDate); | ||||
| 		field_to_json(Obj,"executionTime", executionTime); | ||||
| 	} | ||||
|  | ||||
| 	bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",Name); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| 			field_from_json(Obj,"modelIds",Models); | ||||
| 			field_from_json(Obj,"description",Description); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void BlackListedDevice::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", serialNumber); | ||||
| 		field_to_json(Obj,"author", author); | ||||
| 		field_to_json(Obj,"reason", reason); | ||||
| 		field_to_json(Obj,"created", created); | ||||
| 	} | ||||
|  | ||||
| 	bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"author",author); | ||||
| 			field_from_json(Obj,"reason",reason); | ||||
| 			field_from_json(Obj,"created",created); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"ipAddress", Address); | ||||
| 		field_to_json(Obj,"txBytes", TX); | ||||
| 		field_to_json(Obj,"rxBytes", RX); | ||||
| 		field_to_json(Obj,"messageCount", MessageCount); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"connected", Connected); | ||||
| 		field_to_json(Obj,"firmware", Firmware); | ||||
| 		field_to_json(Obj,"lastContact", LastContact); | ||||
| 		field_to_json(Obj,"associations_2G", Associations_2G); | ||||
| 		field_to_json(Obj,"associations_5G", Associations_5G); | ||||
| 		field_to_json(Obj,"webSocketClients", webSocketClients); | ||||
| 		field_to_json(Obj,"websocketPackets", websocketPackets); | ||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); | ||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
|  | ||||
| 		switch(VerifiedCertificate) { | ||||
| 			case NO_CERTIFICATE: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break; | ||||
| 			case VALID_CERTIFICATE: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "VALID_CERTIFICATE"); break; | ||||
| 			case MISMATCH_SERIAL: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "MISMATCH_SERIAL"); break; | ||||
| 			case VERIFIED: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "VERIFIED"); break; | ||||
| 			default: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| 		field_to_json(Obj,"server", Server); | ||||
| 		field_to_json(Obj,"port", Port); | ||||
| 		field_to_json(Obj,"token",Token); | ||||
| 		field_to_json(Obj,"timeout", TimeOut); | ||||
| 		field_to_json(Obj,"connectionId",ConnectionId); | ||||
| 		field_to_json(Obj,"commandUUID",CommandUUID); | ||||
| 		field_to_json(Obj,"started", Started); | ||||
| 		field_to_json(Obj,"viewport",ViewPort); | ||||
| 		field_to_json(Obj,"password",DevicePassword); | ||||
| 	} | ||||
|  | ||||
| 	void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"commands",commands); | ||||
| 		field_to_json(Obj,"upTimes",upTimes); | ||||
| 		field_to_json(Obj,"memoryUsed",memoryUsed); | ||||
| 		field_to_json(Obj,"load1",load1); | ||||
| 		field_to_json(Obj,"load5",load5); | ||||
| 		field_to_json(Obj,"load15",load15); | ||||
| 		field_to_json(Obj,"vendors",vendors); | ||||
| 		field_to_json(Obj,"status",status); | ||||
| 		field_to_json(Obj,"deviceType",deviceType); | ||||
| 		field_to_json(Obj,"healths",healths); | ||||
| 		field_to_json(Obj,"certificates",certificates); | ||||
| 		field_to_json(Obj,"lastContact",lastContact); | ||||
| 		field_to_json(Obj,"associations",associations); | ||||
| 		field_to_json(Obj,"snapshot",snapshot); | ||||
| 		field_to_json(Obj,"numberOfDevices",numberOfDevices); | ||||
| 	} | ||||
|  | ||||
| 	void Dashboard::reset()  { | ||||
| 		commands.clear(); | ||||
| 		upTimes.clear(); | ||||
| 		memoryUsed.clear(); | ||||
| 		load1.clear(); | ||||
| 		load5.clear(); | ||||
| 		load15.clear(); | ||||
| 		vendors.clear(); | ||||
| 		status.clear(); | ||||
| 		deviceType.clear(); | ||||
| 		healths.clear(); | ||||
| 		certificates.clear(); | ||||
| 		lastContact.clear(); | ||||
| 		associations.clear(); | ||||
| 		numberOfDevices = 0 ; | ||||
| 		snapshot = OpenWifi::Now(); | ||||
| 	} | ||||
|  | ||||
| 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | ||||
| 		field_to_json(Obj,"deviceType", deviceType); | ||||
| 		field_to_json(Obj,"capabilities", capabilities); | ||||
| 	}; | ||||
|  | ||||
| 	void ScriptRequest::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber",serialNumber); | ||||
| 		field_to_json(Obj,"timeout",timeout); | ||||
| 		field_to_json(Obj,"type",type); | ||||
| 		field_to_json(Obj,"script",script); | ||||
| 		field_to_json(Obj,"scriptId",scriptId); | ||||
| 		field_to_json(Obj,"when",when); | ||||
| 	} | ||||
|  | ||||
| 	bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"timeout",timeout); | ||||
| 			field_from_json(Obj,"type",type); | ||||
| 			field_from_json(Obj,"script",script); | ||||
| 			field_from_json(Obj,"scriptId",scriptId); | ||||
| 			field_from_json(Obj,"when",when); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										213
									
								
								src/framework/RESTAPI_GWobjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/framework/RESTAPI_GWobjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,213 @@ | ||||
| // | ||||
| //	License type: BSD 3-Clause License | ||||
| //	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
| // | ||||
| //	Created by Stephane Bourque on 2021-03-04. | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Poco/JSON/Object.h" | ||||
| #include "RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 	enum CertificateValidation { | ||||
| 		NO_CERTIFICATE, | ||||
| 		VALID_CERTIFICATE, | ||||
| 		MISMATCH_SERIAL, | ||||
| 		VERIFIED | ||||
| 	}; | ||||
|  | ||||
| 	struct ConnectionState { | ||||
| 		uint64_t MessageCount = 0 ; | ||||
| 		std::string Address; | ||||
| 		uint64_t UUID = 0 ; | ||||
| 		uint64_t PendingUUID = 0 ; | ||||
| 		uint64_t TX = 0, RX = 0; | ||||
| 		uint64_t Associations_2G=0; | ||||
| 		uint64_t Associations_5G=0; | ||||
| 		bool Connected = false; | ||||
| 		uint64_t LastContact=0; | ||||
| 		std::string Firmware; | ||||
| 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | ||||
| 		std::string Compatible; | ||||
| 		uint64_t 	kafkaClients=0; | ||||
| 		uint64_t 	webSocketClients=0; | ||||
| 		uint64_t 	kafkaPackets=0; | ||||
| 		uint64_t 	websocketPackets=0; | ||||
| 		std::string locale; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Device { | ||||
| 		std::string SerialNumber; | ||||
| 		std::string DeviceType; | ||||
| 		std::string MACAddress; | ||||
| 		std::string Manufacturer; | ||||
| 		std::string Configuration; | ||||
| 		SecurityObjects::NoteInfoVec 	Notes; | ||||
| 		std::string Owner; | ||||
| 		std::string Location; | ||||
| 		std::string Firmware; | ||||
| 		std::string Compatible; | ||||
| 		std::string FWUpdatePolicy; | ||||
| 		uint64_t UUID = 0 ; | ||||
| 		uint64_t CreationTimestamp = 0 ; | ||||
| 		uint64_t LastConfigurationChange = 0 ; | ||||
| 		uint64_t LastConfigurationDownload = 0 ; | ||||
| 		uint64_t LastFWUpdate = 0 ; | ||||
| 		std::string Venue; | ||||
| 		std::string DevicePassword; | ||||
| 		std::string subscriber; | ||||
| 		std::string entity; | ||||
| 		uint64_t 	modified=0; | ||||
| 		std::string locale; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		void Print() const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Statistics { | ||||
| 		std::string SerialNumber; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Recorded = 0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct HealthCheck { | ||||
| 		std::string SerialNumber; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Recorded = 0 ; | ||||
| 		uint64_t 	Sanity = 0 ; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Capabilities { | ||||
| 		std::string Capabilities; | ||||
| 		uint64_t 	FirstUpdate = 0 ; | ||||
| 		uint64_t 	LastUpdate = 0 ; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct DeviceLog { | ||||
| 		enum Level { | ||||
| 			LOG_EMERG = 0,	 /* system is unusable */ | ||||
| 			LOG_ALERT = 1,	 /* action must be taken immediately */ | ||||
| 			LOG_CRIT = 2,	 /* critical conditions */ | ||||
| 			LOG_ERR = 3,	 /* error conditions */ | ||||
| 			LOG_WARNING = 4, /* warning conditions */ | ||||
| 			LOG_NOTICE = 5,	 /* normal but significant condition */ | ||||
| 			LOG_INFO = 6,	 /* informational */ | ||||
| 			LOG_DEBUG = 7	 /* debug-level messages */ | ||||
| 		}; | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Log; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Severity = 0 ; | ||||
| 		uint64_t 	Recorded = 0 ; | ||||
| 		uint64_t 	LogType = 0 ; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct DefaultConfiguration { | ||||
| 		std::string Name; | ||||
| 		std::string Configuration; | ||||
| 		Types::StringVec Models; | ||||
| 		std::string Description; | ||||
| 		uint64_t 	Created; | ||||
| 		uint64_t 	LastModified; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool 		from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct CommandDetails { | ||||
| 		std::string UUID; | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Command; | ||||
| 		std::string Status; | ||||
| 		std::string SubmittedBy; | ||||
| 		std::string Results; | ||||
| 		std::string Details; | ||||
| 		std::string ErrorText; | ||||
| 		uint64_t Submitted = time(nullptr); | ||||
| 		uint64_t Executed = 0; | ||||
| 		uint64_t Completed = 0 ; | ||||
| 		uint64_t RunAt = 0 ; | ||||
| 		uint64_t ErrorCode = 0 ; | ||||
| 		uint64_t Custom = 0 ; | ||||
| 		uint64_t WaitingForFile = 0 ; | ||||
| 		uint64_t AttachDate = 0 ; | ||||
| 		uint64_t AttachSize = 0 ; | ||||
| 		std::string AttachType; | ||||
| 		double 		executionTime = 0.0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct BlackListedDevice { | ||||
| 		std::string serialNumber; | ||||
| 		std::string reason; | ||||
| 		std::string author; | ||||
| 		uint64_t created; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RttySessionDetails { | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Server; | ||||
| 		uint64_t 	Port = 0 ; | ||||
| 		std::string Token; | ||||
| 		uint64_t 	TimeOut = 0 ; | ||||
| 		std::string ConnectionId; | ||||
| 		uint64_t 	Started = 0 ; | ||||
| 		std::string CommandUUID; | ||||
| 		uint64_t 	ViewPort = 0 ; | ||||
| 		std::string DevicePassword; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Dashboard { | ||||
| 		uint64_t 		  snapshot = 0 ; | ||||
| 		uint64_t 		  numberOfDevices = 0 ; | ||||
| 		Types::CountedMap commands; | ||||
| 		Types::CountedMap upTimes; | ||||
| 		Types::CountedMap memoryUsed; | ||||
| 		Types::CountedMap load1; | ||||
| 		Types::CountedMap load5; | ||||
| 		Types::CountedMap load15; | ||||
| 		Types::CountedMap vendors; | ||||
| 		Types::CountedMap status; | ||||
| 		Types::CountedMap deviceType; | ||||
| 		Types::CountedMap healths; | ||||
| 		Types::CountedMap certificates; | ||||
| 		Types::CountedMap lastContact; | ||||
| 		Types::CountedMap associations; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void reset(); | ||||
| 	}; | ||||
|  | ||||
| 	struct CapabilitiesModel { | ||||
| 		std::string deviceType; | ||||
| 		std::string capabilities; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct ScriptRequest { | ||||
| 		uint64_t 	timeout=30; | ||||
| 		std::string serialNumber; | ||||
| 		std::string type; | ||||
| 		std::string script; | ||||
| 		std::string scriptId; | ||||
| 		uint64_t 	when=0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user