mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-11-03 20:27:45 +00:00 
			
		
		
		
	Compare commits
	
		
			260 Commits
		
	
	
		
			release/v2
			...
			v2.6.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					830750f857 | ||
| 
						 | 
					f8d3079f44 | ||
| 
						 | 
					81cec762f7 | ||
| 
						 | 
					a430ad7e71 | ||
| 
						 | 
					d1c13ad2dd | ||
| 
						 | 
					b837e41569 | ||
| 
						 | 
					5e39987e36 | ||
| 
						 | 
					890eb7311a | ||
| 
						 | 
					fc509adf01 | ||
| 
						 | 
					f43198f874 | ||
| 
						 | 
					767331f575 | ||
| 
						 | 
					d26ef6eeba | ||
| 
						 | 
					8c672f058f | ||
| 
						 | 
					3134947b57 | ||
| 
						 | 
					448563ab06 | ||
| 
						 | 
					2a22a35e58 | ||
| 
						 | 
					8e8656a6ae | ||
| 
						 | 
					e745d4efe7 | ||
| 
						 | 
					701e0b50ff | ||
| 
						 | 
					df082a969e | ||
| 
						 | 
					8863d2ecc9 | ||
| 
						 | 
					5e1937ec4f | ||
| 
						 | 
					e679dc7458 | ||
| 
						 | 
					7e1a962b57 | ||
| 
						 | 
					8ad2e12f12 | ||
| 
						 | 
					23d16e619a | ||
| 
						 | 
					760cad9a14 | ||
| 
						 | 
					94997a1f9f | ||
| 
						 | 
					9060fef03d | ||
| 
						 | 
					2f8eb90c5a | ||
| 
						 | 
					c0d0435efa | ||
| 
						 | 
					6942de0475 | ||
| 
						 | 
					cce2528ec4 | ||
| 
						 | 
					3be0fd45d9 | ||
| 
						 | 
					8b1a80ce09 | ||
| 
						 | 
					5e12f00558 | ||
| 
						 | 
					1d534cb974 | ||
| 
						 | 
					a7e9c96f8d | ||
| 
						 | 
					cb3f7a0872 | ||
| 
						 | 
					6ad434c02f | ||
| 
						 | 
					70ddeaf3c1 | ||
| 
						 | 
					56d7c7c767 | ||
| 
						 | 
					62e3ada15c | ||
| 
						 | 
					2beef2daba | ||
| 
						 | 
					4b131465fb | ||
| 
						 | 
					cafc243e55 | ||
| 
						 | 
					5c44134f9d | ||
| 
						 | 
					8ed86d3582 | ||
| 
						 | 
					7e3fb701a0 | ||
| 
						 | 
					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.6.0)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 17)
 | 
			
		||||
 | 
			
		||||
@@ -48,12 +48,15 @@ set(BUILD_SHARED_LIBS 1)
 | 
			
		||||
 | 
			
		||||
add_definitions(-DTIP_SECURITY_SERVICE="1")
 | 
			
		||||
 | 
			
		||||
set(Boost_USE_STATIC_LIBS OFF)
 | 
			
		||||
set(Boost_USE_MULTITHREADED ON)
 | 
			
		||||
set(Boost_USE_STATIC_RUNTIME OFF)
 | 
			
		||||
find_package(Boost REQUIRED system)
 | 
			
		||||
add_compile_options(-Wall -Wextra)
 | 
			
		||||
if(ASAN)
 | 
			
		||||
    add_compile_options(-fsanitize=address)
 | 
			
		||||
    add_link_options(-fsanitize=address)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
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 +75,9 @@ 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/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 +124,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)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -19,6 +19,18 @@ RUN cmake ..
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
RUN cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS fmtlib-build
 | 
			
		||||
 | 
			
		||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
 | 
			
		||||
RUN git clone https://github.com/fmtlib/fmt /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
 | 
			
		||||
@@ -74,10 +86,15 @@ 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 ..
 | 
			
		||||
RUN cmake .. \
 | 
			
		||||
          -Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
 | 
			
		||||
          -DBUILD_SHARED_LIBS=ON
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
 | 
			
		||||
FROM alpine:3.15
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ 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"} \
 | 
			
		||||
@@ -42,6 +42,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"} \
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,14 @@ name: owsec
 | 
			
		||||
version: 0.1.0
 | 
			
		||||
dependencies:
 | 
			
		||||
- name: postgresql
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  version: 10.9.2
 | 
			
		||||
  condition: postgresql.enabled
 | 
			
		||||
- name: mysql
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  version: 8.8.3
 | 
			
		||||
  condition: mysql.enabled
 | 
			
		||||
- name: mariadb
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  version: 9.4.2
 | 
			
		||||
  condition: mariadb.enabled
 | 
			
		||||
 
 | 
			
		||||
@@ -30,3 +30,13 @@ Create chart name and version as used by the chart label.
 | 
			
		||||
{{- define "owsec.chart" -}}
 | 
			
		||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
 | 
			
		||||
{{- end -}}
 | 
			
		||||
 | 
			
		||||
{{- define "owsec.ingress.apiVersion" -}}
 | 
			
		||||
  {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
 | 
			
		||||
      {{- print "networking.k8s.io/v1" -}}
 | 
			
		||||
  {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
 | 
			
		||||
    {{- print "networking.k8s.io/v1beta1" -}}
 | 
			
		||||
  {{- else -}}
 | 
			
		||||
    {{- print "extensions/v1beta1" -}}
 | 
			
		||||
  {{- end -}}
 | 
			
		||||
{{- end -}}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
{{- range $ingress, $ingressValue := .Values.ingresses }}
 | 
			
		||||
{{- if $ingressValue.enabled }}
 | 
			
		||||
---
 | 
			
		||||
apiVersion: extensions/v1beta1
 | 
			
		||||
apiVersion: {{ include "owsec.ingress.apiVersion" $root }}
 | 
			
		||||
kind: Ingress
 | 
			
		||||
metadata:
 | 
			
		||||
  name: {{ include "owsec.fullname" $root }}-{{ $ingress }}
 | 
			
		||||
@@ -36,11 +36,25 @@ spec:
 | 
			
		||||
      paths:
 | 
			
		||||
      {{- range $ingressValue.paths }}
 | 
			
		||||
        - path: {{ .path }}
 | 
			
		||||
          {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
 | 
			
		||||
          pathType: {{ .pathType | default "ImplementationSpecific" }}
 | 
			
		||||
          {{- end }}
 | 
			
		||||
          backend:
 | 
			
		||||
            {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
 | 
			
		||||
            service:
 | 
			
		||||
              name: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
 | 
			
		||||
              port:
 | 
			
		||||
              {{- if kindIs "string" .servicePort }}
 | 
			
		||||
                name: {{ .servicePort }}
 | 
			
		||||
              {{- else }}
 | 
			
		||||
                number: {{ .servicePort }}
 | 
			
		||||
              {{- end }}
 | 
			
		||||
            {{- else }}
 | 
			
		||||
            serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
 | 
			
		||||
            servicePort: {{ .servicePort }}
 | 
			
		||||
            {{- end }}
 | 
			
		||||
      {{- end }}
 | 
			
		||||
  {{- end }}
 | 
			
		||||
 | 
			
		||||
{{- end }}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
			
		||||
images:
 | 
			
		||||
  owsec:
 | 
			
		||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
 | 
			
		||||
    tag: main
 | 
			
		||||
    tag: v2.6.0
 | 
			
		||||
    pullPolicy: Always
 | 
			
		||||
#    regcred:
 | 
			
		||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
			
		||||
@@ -54,6 +54,7 @@ ingresses:
 | 
			
		||||
    - restapi.chart-example.local
 | 
			
		||||
    paths:
 | 
			
		||||
    - path: /
 | 
			
		||||
      pathType: ImplementationSpecific
 | 
			
		||||
      serviceName: owsec
 | 
			
		||||
      servicePort: restapi
 | 
			
		||||
 | 
			
		||||
@@ -166,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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,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
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void ActionLinkManager::run() {
 | 
			
		||||
        Running_ = true ;
 | 
			
		||||
        Utils::SetThreadName("action-mgr");
 | 
			
		||||
 | 
			
		||||
        while(Running_) {
 | 
			
		||||
            Poco::Thread::trySleep(2000);
 | 
			
		||||
@@ -48,7 +49,8 @@ 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;
 | 
			
		||||
                }
 | 
			
		||||
@@ -56,7 +58,7 @@ namespace OpenWifi {
 | 
			
		||||
                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));
 | 
			
		||||
                                Logger().information(fmt::format("Send password reset link to {}",UInfo.email));
 | 
			
		||||
                            }
 | 
			
		||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -64,7 +66,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
                    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));
 | 
			
		||||
                                Logger().information(fmt::format("Send email verification link to {}",UInfo.email));
 | 
			
		||||
                            }
 | 
			
		||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -72,7 +74,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
                    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));
 | 
			
		||||
                                Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email));
 | 
			
		||||
                            }
 | 
			
		||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -80,7 +82,15 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
                    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));
 | 
			
		||||
                                Logger().information(fmt::format("Send subscriber email verification link to {}",UInfo.email));
 | 
			
		||||
                            }
 | 
			
		||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
 | 
			
		||||
                        if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::SIGNUP_VERIFICATION)) {
 | 
			
		||||
                            Logger().information(fmt::format("Send new subscriber email verification link to {}",UInfo.email));
 | 
			
		||||
                        }
 | 
			
		||||
                        StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,17 +16,18 @@ namespace OpenWifi {
 | 
			
		||||
            FORGOT_PASSWORD,
 | 
			
		||||
            VERIFY_EMAIL,
 | 
			
		||||
            SUB_FORGOT_PASSWORD,
 | 
			
		||||
            SUB_VERIFY_EMAIL
 | 
			
		||||
            SUB_VERIFY_EMAIL,
 | 
			
		||||
            SUB_SIGNUP
 | 
			
		||||
        };
 | 
			
		||||
*/
 | 
			
		||||
        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_;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	int AuthService::AccessTypeToInt(ACCESS_TYPE T) {
 | 
			
		||||
		switch (T) {
 | 
			
		||||
		case USERNAME: return 1;
 | 
			
		||||
@@ -42,18 +43,19 @@ 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...");
 | 
			
		||||
        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,}$");
 | 
			
		||||
        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,}$");
 | 
			
		||||
        SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1);
 | 
			
		||||
        SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html");
 | 
			
		||||
        SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html");
 | 
			
		||||
 | 
			
		||||
@@ -64,6 +66,82 @@ namespace OpenWifi {
 | 
			
		||||
		Logger().notice("Stopping...");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::RefreshUserToken(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()->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, bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard	Guard(Mutex_);
 | 
			
		||||
@@ -85,7 +163,8 @@ namespace OpenWifi {
 | 
			
		||||
            if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
                if(RevocationDate!=0)
 | 
			
		||||
                    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;
 | 
			
		||||
@@ -120,7 +199,8 @@ namespace OpenWifi {
 | 
			
		||||
            if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
                if(RevocationDate!=0)
 | 
			
		||||
                    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;
 | 
			
		||||
@@ -180,7 +260,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 +272,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 +284,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 +305,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 +472,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,14 +501,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()->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 );
 | 
			
		||||
 | 
			
		||||
@@ -438,7 +518,7 @@ namespace OpenWifi {
 | 
			
		||||
        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 +547,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 update has taken place if need be, now generate the token.
 | 
			
		||||
            UInfo.userinfo.lastLogin=std::time(nullptr);
 | 
			
		||||
            UInfo.userinfo.lastLogin=OpenWifi::Now();
 | 
			
		||||
            StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
            CreateSubToken(UserName, UInfo );
 | 
			
		||||
 | 
			
		||||
@@ -504,7 +584,7 @@ namespace OpenWifi {
 | 
			
		||||
                        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);
 | 
			
		||||
                        UInfo.waitingForEmailCheck = true;
 | 
			
		||||
@@ -539,13 +619,24 @@ namespace OpenWifi {
 | 
			
		||||
                    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);
 | 
			
		||||
                    UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
                case 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 ;
 | 
			
		||||
                    SMTPMailerService()->SendMessage(UInfo.email, "signup_verification.txt", Attrs);
 | 
			
		||||
                    UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
@@ -558,13 +649,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 +664,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,7 +686,7 @@ 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;
 | 
			
		||||
@@ -613,7 +706,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,8 @@ namespace OpenWifi{
 | 
			
		||||
 | 
			
		||||
        enum EMAIL_REASON {
 | 
			
		||||
            FORGOT_PASSWORD,
 | 
			
		||||
            EMAIL_VERIFICATION
 | 
			
		||||
            EMAIL_VERIFICATION,
 | 
			
		||||
            SIGNUP_VERIFICATION
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        static ACCESS_TYPE IntToAccessType(int C);
 | 
			
		||||
@@ -112,8 +113,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 +128,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
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/Daemon.h
									
									
									
									
									
								
							@@ -24,11 +24,11 @@
 | 
			
		||||
 | 
			
		||||
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 +40,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 +49,9 @@ namespace OpenWifi {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline Daemon * Daemon() { return Daemon::instance(); }
 | 
			
		||||
    inline void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
			
		||||
        Daemon()->PostInitialization(self);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_DAEMON_H
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,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);
 | 
			
		||||
@@ -65,7 +65,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 +107,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
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,8 @@ namespace OpenWifi {
 | 
			
		||||
            return RequestResetPassword(Link);
 | 
			
		||||
        else if(Action=="email_verification")
 | 
			
		||||
            return DoEmailVerification(Link);
 | 
			
		||||
        else if(Action=="signup_verification")
 | 
			
		||||
            return DoNewSubVerification(Link);
 | 
			
		||||
        else
 | 
			
		||||
            return DoReturnA404();
 | 
			
		||||
    }
 | 
			
		||||
@@ -34,18 +36,28 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
        if(Action=="password_reset")
 | 
			
		||||
            return CompleteResetPassword();
 | 
			
		||||
        else if(Action=="signup_completion")
 | 
			
		||||
            return CompleteSubVerification();
 | 
			
		||||
        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 +65,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 +113,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 +130,101 @@ 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;
 | 
			
		||||
            Body.set("signupUUID", UInfo.signingUp);
 | 
			
		||||
            OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
 | 
			
		||||
                                            {
 | 
			
		||||
                                                {"signupUUID", UInfo.signingUp} ,
 | 
			
		||||
                                                {"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 +238,12 @@ 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
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,13 @@ 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 CompleteResetPassword();
 | 
			
		||||
        void CompleteSubVerification();
 | 
			
		||||
        void DoEmailVerification(SecurityObjects::ActionLink &Link);
 | 
			
		||||
        void DoReturnA404();
 | 
			
		||||
        void DoNewSubVerification(SecurityObjects::ActionLink &Link);
 | 
			
		||||
 | 
			
		||||
        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"
 | 
			
		||||
@@ -22,12 +22,12 @@ namespace OpenWifi {
 | 
			
		||||
        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);
 | 
			
		||||
                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,16 @@
 | 
			
		||||
#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::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 +49,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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								src/RESTAPI/RESTAPI_signup_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/RESTAPI/RESTAPI_signup_handler.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
//
 | 
			
		||||
// 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");
 | 
			
		||||
        if(UserName.empty() || signupUUID.empty() || owner.empty()) {
 | 
			
		||||
            Logger().error("Signup requires: email, signupUUID, 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 = 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);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Poco::JSON::Object RetObj;
 | 
			
		||||
            RetObj.set(RESTAPI::Protocol::USERS, ArrayObj);
 | 
			
		||||
            return ReturnObject(RetObj);
 | 
			
		||||
                    Users.users.emplace_back(UInfo);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            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);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Poco::JSON::Object RetObj;
 | 
			
		||||
            RetObj.set(RESTAPI::Protocol::USERS, ArrayObj);
 | 
			
		||||
            return ReturnObject(RetObj);
 | 
			
		||||
                    Users.users.emplace_back(UInfo);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            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,7 @@ 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);
 | 
			
		||||
 | 
			
		||||
		switch(VerifiedCertificate) {
 | 
			
		||||
			case NO_CERTIFICATE:
 | 
			
		||||
@@ -256,7 +264,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 +272,100 @@ 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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
		field_to_json(Obj,"policy",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,"policy",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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		uint64_t 	webSocketClients=0;
 | 
			
		||||
		uint64_t 	kafkaPackets=0;
 | 
			
		||||
		uint64_t 	websocketPackets=0;
 | 
			
		||||
		std::string locale;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -59,9 +60,14 @@ 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;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -118,7 +124,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 +156,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 +199,53 @@ 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;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
		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);
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,6 +488,100 @@ 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);
 | 
			
		||||
@@ -307,9 +594,12 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
        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,"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) {
 | 
			
		||||
@@ -325,9 +615,32 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
            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(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        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 (...) {
 | 
			
		||||
 | 
			
		||||
@@ -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);
 | 
			
		||||
			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,22 @@ 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
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        struct ActionLink {
 | 
			
		||||
@@ -245,14 +263,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 +278,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 +288,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 +300,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 +311,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
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,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 +45,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 +58,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 +71,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
                Logger().debug(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));
 | 
			
		||||
            Logger().debug(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));
 | 
			
		||||
        Logger().debug(fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
        form.add("To", PhoneNumber);
 | 
			
		||||
        form.add("From", PhoneNumber_);
 | 
			
		||||
        form.add("Body","This is from twillio");
 | 
			
		||||
        form.add("Body", Message);
 | 
			
		||||
 | 
			
		||||
        form.prepareSubmit(req);
 | 
			
		||||
        std::ostream& ostr = session.sendRequest(req);
 | 
			
		||||
@@ -64,12 +64,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));
 | 
			
		||||
            Logger().information(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()));
 | 
			
		||||
            Logger().information(fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str()));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,10 @@ 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);
 | 
			
		||||
            Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -47,15 +47,15 @@ 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.");
 | 
			
		||||
        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),
 | 
			
		||||
@@ -65,6 +65,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void SMTPMailerService::run() {
 | 
			
		||||
        Running_ = true;
 | 
			
		||||
        Utils::SetThreadName("smtp-mailer");
 | 
			
		||||
        while(Running_) {
 | 
			
		||||
 | 
			
		||||
            Poco::Thread::trySleep(10000);
 | 
			
		||||
@@ -80,17 +81,17 @@ 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_)) {
 | 
			
		||||
                uint64_t now = OpenWifi::Now();
 | 
			
		||||
                if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) {
 | 
			
		||||
                    if (SendIt(*i)) {
 | 
			
		||||
                        Logger().information(Poco::format("Attempting to deliver for mail '%s'.", Recipient));
 | 
			
		||||
                        Logger().information(fmt::format("Attempting to deliver for mail '{}'.", Recipient));
 | 
			
		||||
                        i = Messages_.erase(i);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        i->LastTry = Now;
 | 
			
		||||
                        i->LastTry = now;
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
                } 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_) {
 | 
			
		||||
                    Logger().information(fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient));
 | 
			
		||||
                    i = Messages_.erase(i);
 | 
			
		||||
                } else {
 | 
			
		||||
                    ++i;
 | 
			
		||||
@@ -121,7 +122,7 @@ namespace OpenWifi {
 | 
			
		||||
                TheSender = Sender_ ;
 | 
			
		||||
            }
 | 
			
		||||
            Message.setSender( TheSender );
 | 
			
		||||
            Logger().information(Poco::format("Sending message to:%s from %s",Recipient,TheSender));
 | 
			
		||||
            Logger().information(fmt::format("Sending message to:{} from {}",Recipient,TheSender));
 | 
			
		||||
            Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient));
 | 
			
		||||
            Message.setSubject(Msg.Attrs.find(SUBJECT)->second);
 | 
			
		||||
 | 
			
		||||
@@ -130,9 +131,11 @@ namespace OpenWifi {
 | 
			
		||||
                Message.addContent(new Poco::Net::StringPartSource(Content));
 | 
			
		||||
            } else {
 | 
			
		||||
                std::string Content = Utils::LoadFile(Msg.File);
 | 
			
		||||
                // std::cout << "Mailing " << Content << std::endl;
 | 
			
		||||
                Types::StringPairVec    Variables;
 | 
			
		||||
                FillVariables(Msg.Attrs, Variables);
 | 
			
		||||
                Utils::ReplaceVariables(Content, Variables);
 | 
			
		||||
                // std::cout << "Mailing " << Content << std::endl;
 | 
			
		||||
                Message.addContent(new Poco::Net::StringPartSource(Content));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -145,7 +148,7 @@ namespace OpenWifi {
 | 
			
		||||
                    Poco::StreamCopier::copyStream(IF, OS);
 | 
			
		||||
                    Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png"));
 | 
			
		||||
                } catch (...) {
 | 
			
		||||
                    Logger().warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName()));
 | 
			
		||||
                    Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName()));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -175,7 +178,7 @@ namespace OpenWifi {
 | 
			
		||||
            Logger().log(E);
 | 
			
		||||
        }
 | 
			
		||||
        catch (const std::exception &E) {
 | 
			
		||||
            Logger().warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what()));
 | 
			
		||||
            Logger().warning(fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what()));
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -84,9 +84,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";
 | 
			
		||||
 
 | 
			
		||||
@@ -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.";
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,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());
 | 
			
		||||
@@ -62,7 +62,8 @@ namespace OpenWifi {
 | 
			
		||||
        StorageClass::Stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Archiver::onTimer(Poco::Timer &timer) {
 | 
			
		||||
    void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) {
 | 
			
		||||
        Utils::SetThreadName("archiver");
 | 
			
		||||
        Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER");
 | 
			
		||||
        logger.information("Squiggy the DB: removing old tokens.");
 | 
			
		||||
        StorageService()->SubTokenDB().CleanExpiredTokens();
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,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 +52,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 +75,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 +92,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 +122,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"(
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
	"$id": "https://openwrt.org/ucentral.schema.json",
 | 
			
		||||
	"$schema": "http://json-schema.org/draft-07/schema#",
 | 
			
		||||
@@ -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": [
 | 
			
		||||
@@ -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"
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
@@ -2317,16 +2610,32 @@ namespace OpenWifi {
 | 
			
		||||
}
 | 
			
		||||
)"_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
											
										
									
								
							
							
								
								
									
										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);
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@@ -1,68 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-09-12.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::RESTAPI::Errors {
 | 
			
		||||
    static const std::string MissingUUID{"Missing UUID."};
 | 
			
		||||
    static const std::string MissingSerialNumber{"Missing Serial Number."};
 | 
			
		||||
    static const std::string InternalError{"Internal error. Please try later."};
 | 
			
		||||
    static const std::string InvalidJSONDocument{"Invalid JSON document."};
 | 
			
		||||
    static const std::string UnsupportedHTTPMethod{"Unsupported HTTP Method"};
 | 
			
		||||
    static const std::string StillInUse{"Element still in use."};
 | 
			
		||||
    static const std::string CouldNotBeDeleted{"Element could not be deleted."};
 | 
			
		||||
    static const std::string NameMustBeSet{"The name property must be set."};
 | 
			
		||||
    static const std::string ConfigBlockInvalid{"Configuration block type invalid."};
 | 
			
		||||
    static const std::string UnknownId{"Unknown UUID."};
 | 
			
		||||
    static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."};
 | 
			
		||||
    static const std::string RecordNotCreated{"Record could not be created."};
 | 
			
		||||
    static const std::string RecordNotUpdated{"Record could not be updated."};
 | 
			
		||||
    static const std::string UnknownManagementPolicyUUID{"Unknown management policy UUID."};
 | 
			
		||||
    static const std::string CannotDeleteRoot{"Root Entity cannot be removed, only modified."};
 | 
			
		||||
    static const std::string MustCreateRootFirst{"Root entity must be created first."};
 | 
			
		||||
    static const std::string ParentUUIDMustExist{"Parent UUID must exist."};
 | 
			
		||||
    static const std::string ConfigurationMustExist{"Configuration must exist."};
 | 
			
		||||
    static const std::string MissingOrInvalidParameters{"Invalid or missing parameters."};
 | 
			
		||||
    static const std::string UnknownSerialNumber{"Unknown Serial Number."};
 | 
			
		||||
    static const std::string InvalidSerialNumber{"Invalid Serial Number."};
 | 
			
		||||
    static const std::string SerialNumberExists{"Serial Number already exists."};
 | 
			
		||||
    static const std::string ValidNonRootUUID{"Must be a non-root, and valid UUID."};
 | 
			
		||||
    static const std::string VenueMustExist{"Venue does not exist."};
 | 
			
		||||
    static const std::string NotBoth{"You cannot specify both Entity and Venue"};
 | 
			
		||||
    static const std::string EntityMustExist{"Entity must exist."};
 | 
			
		||||
    static const std::string ParentOrEntityMustBeSet{"Parent or Entity must be set."};
 | 
			
		||||
    static const std::string ContactMustExist{"Contact must exist."};
 | 
			
		||||
    static const std::string LocationMustExist{"Location must exist."};
 | 
			
		||||
    static const std::string OnlyWSSupported{"This endpoint only supports WebSocket."};
 | 
			
		||||
    static const std::string SerialNumberMismatch{"Serial Number mismatch."};
 | 
			
		||||
    static const std::string InvalidCommand{"Invalid command."};
 | 
			
		||||
    static const std::string NoRecordsDeleted{"No records deleted."};
 | 
			
		||||
    static const std::string DeviceNotConnected{"Device is not currently connected."};
 | 
			
		||||
    static const std::string CannotCreateWS{"Telemetry system could not create WS endpoint. Please try again."};
 | 
			
		||||
    static const std::string BothDeviceTypeRevision{"Both deviceType and revision must be set."};
 | 
			
		||||
    static const std::string IdOrSerialEmpty{"SerialNumber and Id must not be empty."};
 | 
			
		||||
    static const std::string MissingUserID{"Missing user ID."};
 | 
			
		||||
    static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
 | 
			
		||||
    static const std::string InvalidUserRole{"Invalid userRole."};
 | 
			
		||||
    static const std::string InvalidEmailAddress{"Invalid email address."};
 | 
			
		||||
    static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
 | 
			
		||||
    static const std::string InvalidIPRanges{"Invalid IP range specifications."};
 | 
			
		||||
    static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
 | 
			
		||||
    static const std::string NeedMobileNumber{"You must provide at least one validated phone number."};
 | 
			
		||||
    static const std::string BadMFAMethod{"MFA only supports sms or email."};
 | 
			
		||||
    static const std::string InvalidCredentials{"Invalid credentials (username/password)."};
 | 
			
		||||
    static const std::string InvalidPassword{"Password does not conform to basic password rules."};
 | 
			
		||||
    static const std::string UserPendingVerification{"User access denied pending email verification."};
 | 
			
		||||
    static const std::string PasswordMustBeChanged{"Password must be changed."};
 | 
			
		||||
    static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
 | 
			
		||||
    static const std::string MissingAuthenticationInformation{"Missing authentication information."};
 | 
			
		||||
    static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
 | 
			
		||||
    static const std::string ExpiredToken{"Token has expired, user must login."};
 | 
			
		||||
    static const std::string SubscriberMustExist{"Subscriber must exist."};
 | 
			
		||||
    static const std::string AuthenticatorVerificationIncomplete{"Authenticator validation is not complete."};
 | 
			
		||||
    static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."};
 | 
			
		||||
    static const std::string SMSCouldNotValidate{"Code and number could not be validated"};
 | 
			
		||||
    static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,139 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//	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
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::RESTAPI::Protocol {
 | 
			
		||||
	static const char * CAPABILITIES = "capabilities";
 | 
			
		||||
	static const char * LOGS = "logs";
 | 
			
		||||
	static const char * HEALTHCHECKS = "healthchecks";
 | 
			
		||||
	static const char * STATISTICS = "statistics";
 | 
			
		||||
	static const char * STATUS = "status";
 | 
			
		||||
	static const char * SERIALNUMBER = "serialNumber";
 | 
			
		||||
	static const char * PERFORM = "perform";
 | 
			
		||||
	static const char * CONFIGURE = "configure";
 | 
			
		||||
	static const char * UPGRADE = "upgrade";
 | 
			
		||||
	static const char * REBOOT = "reboot";
 | 
			
		||||
	static const char * FACTORY = "factory";
 | 
			
		||||
	static const char * LEDS = "leds";
 | 
			
		||||
	static const char * TRACE = "trace";
 | 
			
		||||
	static const char * REQUEST = "request";
 | 
			
		||||
	static const char * WIFISCAN = "wifiscan";
 | 
			
		||||
	static const char * EVENTQUEUE = "eventqueue";
 | 
			
		||||
	static const char * RTTY = "rtty";
 | 
			
		||||
	static const char * COMMAND = "command";
 | 
			
		||||
	static const char * STARTDATE = "startDate";
 | 
			
		||||
	static const char * ENDDATE = "endDate";
 | 
			
		||||
	static const char * OFFSET = "offset";
 | 
			
		||||
	static const char * LIMIT = "limit";
 | 
			
		||||
	static const char * LIFETIME = "lifetime";
 | 
			
		||||
	static const char * UUID = "UUID";
 | 
			
		||||
	static const char * DATA = "data";
 | 
			
		||||
	static const char * CONFIGURATION = "configuration";
 | 
			
		||||
	static const char * WHEN = "when";
 | 
			
		||||
	static const char * URI = "uri";
 | 
			
		||||
	static const char * LOGTYPE = "logType";
 | 
			
		||||
	static const char * VALUES = "values";
 | 
			
		||||
	static const char * TYPES = "types";
 | 
			
		||||
	static const char * PAYLOAD = "payload";
 | 
			
		||||
	static const char * KEEPREDIRECTOR = "keepRedirector";
 | 
			
		||||
	static const char * NETWORK = "network";
 | 
			
		||||
	static const char * INTERFACE = "interface";
 | 
			
		||||
	static const char * BANDS = "bands";
 | 
			
		||||
	static const char * CHANNELS = "channels";
 | 
			
		||||
	static const char * VERBOSE = "verbose";
 | 
			
		||||
	static const char * MESSAGE = "message";
 | 
			
		||||
	static const char * STATE = "state";
 | 
			
		||||
	static const char * HEALTHCHECK = "healthcheck";
 | 
			
		||||
	static const char * PCAP_FILE_TYPE = "pcap";
 | 
			
		||||
	static const char * DURATION = "duration";
 | 
			
		||||
	static const char * NUMBEROFPACKETS = "numberOfPackets";
 | 
			
		||||
	static const char * FILTER = "filter";
 | 
			
		||||
	static const char * SELECT = "select";
 | 
			
		||||
	static const char * SERIALONLY = "serialOnly";
 | 
			
		||||
	static const char * COUNTONLY = "countOnly";
 | 
			
		||||
	static const char * DEVICEWITHSTATUS = "deviceWithStatus";
 | 
			
		||||
	static const char * DEVICESWITHSTATUS = "devicesWithStatus";
 | 
			
		||||
	static const char * DEVICES = "devices";
 | 
			
		||||
	static const char * COUNT = "count";
 | 
			
		||||
	static const char * SERIALNUMBERS = "serialNumbers";
 | 
			
		||||
	static const char * CONFIGURATIONS = "configurations";
 | 
			
		||||
	static const char * NAME = "name";
 | 
			
		||||
	static const char * COMMANDS = "commands";
 | 
			
		||||
	static const char * COMMANDUUID = "commandUUID";
 | 
			
		||||
	static const char * FIRMWARES = "firmwares";
 | 
			
		||||
	static const char * TOPIC = "topic";
 | 
			
		||||
	static const char * HOST = "host";
 | 
			
		||||
	static const char * OS = "os";
 | 
			
		||||
	static const char * HOSTNAME = "hostname";
 | 
			
		||||
	static const char * PROCESSORS = "processors";
 | 
			
		||||
	static const char * REASON = "reason";
 | 
			
		||||
	static const char * RELOAD = "reload";
 | 
			
		||||
	static const char * SUBSYSTEMS = "subsystems";
 | 
			
		||||
	static const char * FILEUUID = "uuid";
 | 
			
		||||
	static const char * USERID = "userId";
 | 
			
		||||
	static const char * PASSWORD = "password";
 | 
			
		||||
	static const char * TOKEN = "token";
 | 
			
		||||
	static const char * SETLOGLEVEL = "setloglevel";
 | 
			
		||||
	static const char * GETLOGLEVELS = "getloglevels";
 | 
			
		||||
	static const char * GETSUBSYSTEMNAMES = "getsubsystemnames";
 | 
			
		||||
	static const char * GETLOGLEVELNAMES = "getloglevelnames";
 | 
			
		||||
	static const char * STATS = "stats";
 | 
			
		||||
	static const char * PING = "ping";
 | 
			
		||||
	static const char * PARAMETERS = "parameters";
 | 
			
		||||
	static const char * VALUE = "value";
 | 
			
		||||
	static const char * LASTONLY = "lastOnly";
 | 
			
		||||
	static const char * NEWEST = "newest";
 | 
			
		||||
	static const char * ACTIVESCAN = "activeScan";
 | 
			
		||||
	static const char * OVERRIDEDFS = "override_dfs";
 | 
			
		||||
	static const char * LIST = "list";
 | 
			
		||||
	static const char * TAG = "tag";
 | 
			
		||||
	static const char * TAGLIST = "tagList";
 | 
			
		||||
    static const char * DESCRIPTION = "description";
 | 
			
		||||
    static const char * NOTES = "notes";
 | 
			
		||||
    static const char * DEVICETYPE = "deviceType";
 | 
			
		||||
    static const char * REVISION = "revision";
 | 
			
		||||
    static const char * AGES = "ages";
 | 
			
		||||
    static const char * REVISIONS = "revisions";
 | 
			
		||||
    static const char * DEVICETYPES = "deviceTypes";
 | 
			
		||||
    static const char * LATESTONLY = "latestOnly";
 | 
			
		||||
    static const char * IDONLY = "idOnly";
 | 
			
		||||
    static const char * REVISIONSET = "revisionSet";
 | 
			
		||||
    static const char * DEVICESET = "deviceSet";
 | 
			
		||||
    static const char * HISTORY = "history";
 | 
			
		||||
    static const char * ID = "id";
 | 
			
		||||
    static const char * VERSION = "version";
 | 
			
		||||
    static const char * TIMES = "times";
 | 
			
		||||
    static const char * UPTIME = "uptime";
 | 
			
		||||
    static const char * START = "start";
 | 
			
		||||
 | 
			
		||||
    static const char * NEWPASSWORD = "newPassword";
 | 
			
		||||
    static const char * USERS = "users";
 | 
			
		||||
    static const char * WITHEXTENDEDINFO = "withExtendedInfo";
 | 
			
		||||
 | 
			
		||||
    static const char * ERRORTEXT = "errorText";
 | 
			
		||||
    static const char * ERRORCODE = "errorCode";
 | 
			
		||||
    static const char * AVATARID = "avatarId";
 | 
			
		||||
    static const char * UNNAMED = "(unnamed)";
 | 
			
		||||
    static const char * UNSPECIFIED = "(unspecified)";
 | 
			
		||||
    static const char * CONTENTDISPOSITION = "Content-Disposition";
 | 
			
		||||
    static const char * CONTENTTYPE = "Content-Type";
 | 
			
		||||
 | 
			
		||||
    static const char * REQUIREMENTS = "requirements";
 | 
			
		||||
    static const char * PASSWORDPATTERN = "passwordPattern";
 | 
			
		||||
    static const char * ACCESSPOLICY = "accessPolicy";
 | 
			
		||||
    static const char * PASSWORDPOLICY = "passwordPolicy";
 | 
			
		||||
    static const char * FORGOTPASSWORD = "forgotPassword";
 | 
			
		||||
    static const char * RESENDMFACODE = "resendMFACode";
 | 
			
		||||
    static const char * COMPLETEMFACHALLENGE = "completeMFAChallenge";
 | 
			
		||||
    static const char * ME = "me";
 | 
			
		||||
    static const char * TELEMETRY = "telemetry";
 | 
			
		||||
    static const char * INTERVAL = "interval";
 | 
			
		||||
    static const char * UI = "UI";
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -51,13 +51,14 @@ namespace OpenWifi {
 | 
			
		||||
            Pool_->shutdown();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DBType Type() const { return dbType_; };
 | 
			
		||||
    private:
 | 
			
		||||
        inline int Setup_SQLite();
 | 
			
		||||
        inline int Setup_MySQL();
 | 
			
		||||
        inline int Setup_PostgreSQL();
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
    	Poco::SharedPtr<Poco::Data::SessionPool>    Pool_;
 | 
			
		||||
    	std::unique_ptr<Poco::Data::SessionPool>    Pool_;
 | 
			
		||||
        Poco::Data::SQLite::Connector  	            SQLiteConn_;
 | 
			
		||||
        Poco::Data::PostgreSQL::Connector           PostgresConn_;
 | 
			
		||||
        Poco::Data::MySQL::Connector                MySQLConn_;
 | 
			
		||||
@@ -73,18 +74,22 @@ namespace OpenWifi {
 | 
			
		||||
        Logger().notice("SQLite StorageClass enabled.");
 | 
			
		||||
        dbType_ = sqlite;
 | 
			
		||||
        auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db");
 | 
			
		||||
        auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64);
 | 
			
		||||
        auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60);
 | 
			
		||||
        SQLiteConn_.registerConnector();
 | 
			
		||||
        Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 4, NumSessions, IdleTime));
 | 
			
		||||
        int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64);
 | 
			
		||||
        int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60);
 | 
			
		||||
 | 
			
		||||
        Poco::Data::SQLite::Connector::registerConnector();
 | 
			
		||||
//        Pool_ = std::make_unique<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
 | 
			
		||||
//                                                                                     (int)NumSessions, (int)IdleTime));
 | 
			
		||||
        Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
 | 
			
		||||
                                                                                     (int)NumSessions, (int)IdleTime);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline int StorageClass::Setup_MySQL() {
 | 
			
		||||
        Logger().notice("MySQL StorageClass enabled.");
 | 
			
		||||
        dbType_ = mysql;
 | 
			
		||||
        auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64);
 | 
			
		||||
        auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60);
 | 
			
		||||
        int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64);
 | 
			
		||||
        int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60);
 | 
			
		||||
        auto Host = MicroService::instance().ConfigGetString("storage.type.mysql.host");
 | 
			
		||||
        auto Username = MicroService::instance().ConfigGetString("storage.type.mysql.username");
 | 
			
		||||
        auto Password = MicroService::instance().ConfigGetString("storage.type.mysql.password");
 | 
			
		||||
@@ -99,8 +104,8 @@ namespace OpenWifi {
 | 
			
		||||
                ";port=" + Port +
 | 
			
		||||
                ";compress=true;auto-reconnect=true";
 | 
			
		||||
 | 
			
		||||
        MySQLConn_.registerConnector();
 | 
			
		||||
        Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(MySQLConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
 | 
			
		||||
        Poco::Data::MySQL::Connector::registerConnector();
 | 
			
		||||
        Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8, NumSessions, IdleTime);
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -108,8 +113,8 @@ namespace OpenWifi {
 | 
			
		||||
    inline int StorageClass::Setup_PostgreSQL() {
 | 
			
		||||
        Logger().notice("PostgreSQL StorageClass enabled.");
 | 
			
		||||
        dbType_ = pgsql;
 | 
			
		||||
        auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64);
 | 
			
		||||
        auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60);
 | 
			
		||||
        int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64);
 | 
			
		||||
        int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60);
 | 
			
		||||
        auto Host = MicroService::instance().ConfigGetString("storage.type.postgresql.host");
 | 
			
		||||
        auto Username = MicroService::instance().ConfigGetString("storage.type.postgresql.username");
 | 
			
		||||
        auto Password = MicroService::instance().ConfigGetString("storage.type.postgresql.password");
 | 
			
		||||
@@ -125,8 +130,8 @@ namespace OpenWifi {
 | 
			
		||||
                " port=" + Port +
 | 
			
		||||
                " connect_timeout=" + ConnectionTimeout;
 | 
			
		||||
 | 
			
		||||
        PostgresConn_.registerConnector();
 | 
			
		||||
        Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(PostgresConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
 | 
			
		||||
        Poco::Data::PostgreSQL::Connector::registerConnector();
 | 
			
		||||
        Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8, NumSessions, IdleTime);
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										193
									
								
								src/framework/WebSocketClientNotifications.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								src/framework/WebSocketClientNotifications.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2022-05-05.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	struct WebNotificationSingleDevice {
 | 
			
		||||
		std::string		serialNumber;
 | 
			
		||||
		inline void to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
			try {
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
				return true;
 | 
			
		||||
			} catch (...) {
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct WebNotificationSingleDeviceConfigurationChange {
 | 
			
		||||
		std::string		serialNumber;
 | 
			
		||||
		uint64_t 		oldUUID;
 | 
			
		||||
		uint64_t 		newUUID;
 | 
			
		||||
 | 
			
		||||
		inline void to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"oldUUID", oldUUID);
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"newUUID", newUUID);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
			try {
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"oldUUID", oldUUID);
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"newUUID", newUUID);
 | 
			
		||||
				return true;
 | 
			
		||||
			} catch (...) {
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct WebNotificationSingleDeviceFirmwareChange {
 | 
			
		||||
		std::string		serialNumber;
 | 
			
		||||
		std::string		newFirmware;
 | 
			
		||||
		inline void to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
			RESTAPI_utils::field_to_json(Obj,"newFirmware", newFirmware);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
			try {
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
 | 
			
		||||
				RESTAPI_utils::field_from_json(Obj,"newFirmware", newFirmware);
 | 
			
		||||
				return true;
 | 
			
		||||
			} catch (...) {
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline void WebSocketClientNotificationDeviceConfigurationChange(const std::string &SerialNumber, uint64_t oldUUID, uint64_t newUUID) {
 | 
			
		||||
		WebSocketNotification<WebNotificationSingleDeviceConfigurationChange>	N;
 | 
			
		||||
		N.content.serialNumber = SerialNumber;
 | 
			
		||||
		N.content.oldUUID = oldUUID;
 | 
			
		||||
		N.content.newUUID = newUUID;
 | 
			
		||||
		N.type = "device_configuration_upgrade";
 | 
			
		||||
		WebSocketClientServer()->SendNotification(N);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void WebSocketClientNotificationDeviceFirmwareUpdated(const std::string &SerialNumber, const std::string &Firmware) {
 | 
			
		||||
		WebSocketNotification<WebNotificationSingleDeviceFirmwareChange>	N;
 | 
			
		||||
		N.content.serialNumber = SerialNumber;
 | 
			
		||||
		N.content.newFirmware = Firmware;
 | 
			
		||||
		N.type = "device_firmware_upgrade";
 | 
			
		||||
		WebSocketClientServer()->SendNotification(N);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void WebSocketClientNotificationDeviceConnected(const std::string &SerialNumber) {
 | 
			
		||||
		WebSocketNotification<WebNotificationSingleDevice>	N;
 | 
			
		||||
		N.content.serialNumber = SerialNumber;
 | 
			
		||||
		N.type = "device_connection";
 | 
			
		||||
		WebSocketClientServer()->SendNotification(N);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void WebSocketClientNotificationDeviceDisconnected(const std::string & SerialNumber) {
 | 
			
		||||
		WebSocketNotification<WebNotificationSingleDevice>	N;
 | 
			
		||||
		N.content.serialNumber = SerialNumber;
 | 
			
		||||
		N.type = "device_disconnection";
 | 
			
		||||
		WebSocketClientServer()->SendNotification(N);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    struct WebSocketNotificationJobContent {
 | 
			
		||||
        std::string                 title,
 | 
			
		||||
                                    details,
 | 
			
		||||
                                    jobId;
 | 
			
		||||
        std::vector<std::string>    success,
 | 
			
		||||
                                    error,
 | 
			
		||||
                                    warning;
 | 
			
		||||
        uint64_t                    timeStamp=OpenWifi::Now();
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline void WebSocketNotificationJobContent::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"title",title);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"success",success);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"error",error);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"warning",warning);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"details",details);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline bool WebSocketNotificationJobContent::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"title",title);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"success",success);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"error",error);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"warning",warning);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"details",details);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    typedef WebSocketNotification<WebSocketNotificationJobContent>  WebSocketClientNotificationVenueUpdateJob_t;
 | 
			
		||||
 | 
			
		||||
    inline void WebSocketClientNotificationVenueUpdateJobCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpdateJob_t &N) {
 | 
			
		||||
        N.type = "venue_configuration_update";
 | 
			
		||||
        WebSocketClientServer()->SendUserNotification(User,N);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct WebSocketNotificationRebootList {
 | 
			
		||||
        std::string                 title,
 | 
			
		||||
                details,
 | 
			
		||||
                jobId;
 | 
			
		||||
        std::vector<std::string>    success,
 | 
			
		||||
                warning;
 | 
			
		||||
        uint64_t                    timeStamp=OpenWifi::Now();
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    typedef WebSocketNotification<WebSocketNotificationRebootList> WebSocketClientNotificationVenueRebootList_t;
 | 
			
		||||
 | 
			
		||||
    inline void WebSocketNotificationRebootList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"title",title);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"success",success);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"warning",warning);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"details",details);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline bool WebSocketNotificationRebootList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"title",title);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"success",success);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"warning",warning);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"details",details);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void WebSocketClientNotificationVenueRebootCompletionToUser( const std::string & User, WebSocketClientNotificationVenueRebootList_t &N) {
 | 
			
		||||
        N.type = "venue_rebooter";
 | 
			
		||||
        WebSocketClientServer()->SendUserNotification(User,N);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +33,8 @@ namespace ORM {
 | 
			
		||||
        FT_TEXT,
 | 
			
		||||
        FT_VARCHAR,
 | 
			
		||||
        FT_BLOB,
 | 
			
		||||
        FT_BOOLEAN
 | 
			
		||||
        FT_BOOLEAN,
 | 
			
		||||
        FT_REAL
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum Indextype {
 | 
			
		||||
@@ -108,11 +109,13 @@ namespace ORM {
 | 
			
		||||
                    return "LONGBLOB";
 | 
			
		||||
                else if(Type==OpenWifi::DBType::pgsql)
 | 
			
		||||
                    return "BYTEA";
 | 
			
		||||
                else if(Type==OpenWifi::DBType::sqlite)
 | 
			
		||||
                else
 | 
			
		||||
                    return "BLOB";
 | 
			
		||||
            case FT_REAL:
 | 
			
		||||
                return "REAL";
 | 
			
		||||
            default:
 | 
			
		||||
                assert(false);
 | 
			
		||||
                    return "";
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        assert(false);
 | 
			
		||||
        return "";
 | 
			
		||||
@@ -121,14 +124,46 @@ namespace ORM {
 | 
			
		||||
    inline std::string Escape(const std::string &S) {
 | 
			
		||||
        std::string R;
 | 
			
		||||
 | 
			
		||||
        for(const auto &i:S)
 | 
			
		||||
        for(const auto &i:S) {
 | 
			
		||||
            if (i == '\'')
 | 
			
		||||
                R += "''";
 | 
			
		||||
            else
 | 
			
		||||
                R += i;
 | 
			
		||||
        }
 | 
			
		||||
        return R;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline std::string WHERE_AND_(std::string Result) {
 | 
			
		||||
        return Result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) {
 | 
			
		||||
        if constexpr(std::is_same_v<T,std::string>)
 | 
			
		||||
        {
 | 
			
		||||
            if(!Value.empty()) {
 | 
			
		||||
                if(!Result.empty())
 | 
			
		||||
                    Result += " and ";
 | 
			
		||||
                Result += fieldName;
 | 
			
		||||
                Result += '=';
 | 
			
		||||
                Result += "'";
 | 
			
		||||
                Result += Escape(Value);
 | 
			
		||||
                Result += "'";
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if(!Result.empty())
 | 
			
		||||
                Result += " and ";
 | 
			
		||||
            Result += fieldName ;
 | 
			
		||||
            Result += '=';
 | 
			
		||||
            Result += std::to_string(Value);
 | 
			
		||||
        }
 | 
			
		||||
        return WHERE_AND_(Result,args...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Args> std::string WHERE_AND(Args... args) {
 | 
			
		||||
        std::string Result;
 | 
			
		||||
        return WHERE_AND_(Result, args...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE };
 | 
			
		||||
    enum SqlBinaryOp { AND = 0 , OR };
 | 
			
		||||
 | 
			
		||||
@@ -151,13 +186,21 @@ namespace ORM {
 | 
			
		||||
        return S;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline std::string to_string(const Poco::Data::BLOB &blob) {
 | 
			
		||||
        std::string result;
 | 
			
		||||
        result.assign(blob.begin(),blob.end());
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline std::string to_string(const char * S) {
 | 
			
		||||
        return S;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename RecordType> class DBCache {
 | 
			
		||||
    public:
 | 
			
		||||
        DBCache(unsigned Size, unsigned Timeout)
 | 
			
		||||
        DBCache(unsigned Size, unsigned Timeout) :
 | 
			
		||||
            Size_(Size),
 | 
			
		||||
            Timeout_(Timeout)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
@@ -166,7 +209,8 @@ namespace ORM {
 | 
			
		||||
        virtual void UpdateCache(const RecordType &R)=0;
 | 
			
		||||
        virtual void Delete(const std::string &FieldName, const std::string &Value)=0;
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
        size_t          Size_=0;
 | 
			
		||||
        uint64_t        Timeout_=0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <typename RecordTuple, typename RecordType> class DB {
 | 
			
		||||
@@ -182,8 +226,8 @@ namespace ORM {
 | 
			
		||||
            Poco::Logger &L,
 | 
			
		||||
            const char *Prefix,
 | 
			
		||||
            DBCache<RecordType> * Cache=nullptr):
 | 
			
		||||
                Type_(dbtype),
 | 
			
		||||
                TableName_(TableName),
 | 
			
		||||
                Type_(dbtype),
 | 
			
		||||
                Pool_(Pool),
 | 
			
		||||
                Logger_(L),
 | 
			
		||||
                Prefix_(Prefix),
 | 
			
		||||
@@ -195,7 +239,8 @@ namespace ORM {
 | 
			
		||||
            int  Place=0;
 | 
			
		||||
 | 
			
		||||
            for(const auto &i:Fields) {
 | 
			
		||||
                FieldNames_[i.Name] = Place;
 | 
			
		||||
                std::string FieldName = Poco::toLower(i.Name);
 | 
			
		||||
                FieldNames_[FieldName] = Place;
 | 
			
		||||
                if(!first) {
 | 
			
		||||
                    CreateFields_ += ", ";
 | 
			
		||||
                    SelectFields_ += ", ";
 | 
			
		||||
@@ -205,9 +250,9 @@ namespace ORM {
 | 
			
		||||
                    SelectList_ += "(";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                CreateFields_ += i.Name + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : "");
 | 
			
		||||
                SelectFields_ += i.Name ;
 | 
			
		||||
                UpdateFields_ += i.Name + "=?";
 | 
			
		||||
                CreateFields_ += FieldName + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : "");
 | 
			
		||||
                SelectFields_ += FieldName ;
 | 
			
		||||
                UpdateFields_ += FieldName + "=?";
 | 
			
		||||
                SelectList_ += "?";
 | 
			
		||||
                first = false;
 | 
			
		||||
                Place++;
 | 
			
		||||
@@ -222,12 +267,13 @@ namespace ORM {
 | 
			
		||||
                        IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + TableName_+ " (";
 | 
			
		||||
                        bool first_entry=true;
 | 
			
		||||
                        for(const auto &k:j.Entries) {
 | 
			
		||||
                            assert(FieldNames_.find(k.FieldName) != FieldNames_.end());
 | 
			
		||||
                            auto IndexFieldName = Poco::toLower(k.FieldName);
 | 
			
		||||
                            assert(ValidFieldName(IndexFieldName));
 | 
			
		||||
                            if(!first_entry) {
 | 
			
		||||
                                IndexLine += " , ";
 | 
			
		||||
                            }
 | 
			
		||||
                            first_entry = false;
 | 
			
		||||
                            IndexLine += k.FieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ;
 | 
			
		||||
                            IndexLine += IndexFieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ;
 | 
			
		||||
                        }
 | 
			
		||||
                        IndexLine += " )";
 | 
			
		||||
                        IndexCreation_.template emplace_back(IndexLine);
 | 
			
		||||
@@ -242,12 +288,13 @@ namespace ORM {
 | 
			
		||||
                        IndexLine += " INDEX " + j.Name + " ( " ;
 | 
			
		||||
                        bool first_entry=true;
 | 
			
		||||
                        for(const auto &k:j.Entries) {
 | 
			
		||||
                            assert(FieldNames_.find(k.FieldName) != FieldNames_.end());
 | 
			
		||||
                            auto IndexFieldName = Poco::toLower(k.FieldName);
 | 
			
		||||
                            assert(FieldNames_.find(IndexFieldName) != FieldNames_.end());
 | 
			
		||||
                            if(!first_entry) {
 | 
			
		||||
                                IndexLine += " ,";
 | 
			
		||||
                            }
 | 
			
		||||
                            first_entry = false;
 | 
			
		||||
                            IndexLine += k.FieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC");
 | 
			
		||||
                            IndexLine += IndexFieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC");
 | 
			
		||||
                        }
 | 
			
		||||
                        IndexLine += " ) ";
 | 
			
		||||
                    }
 | 
			
		||||
@@ -262,27 +309,27 @@ namespace ORM {
 | 
			
		||||
        [[nodiscard]] const std::string & UpdateFields() const { return UpdateFields_; };
 | 
			
		||||
 | 
			
		||||
        inline std::string OP(field_name_t F, SqlComparison O , bool V) {
 | 
			
		||||
            assert( FieldNames_.find(F) != FieldNames_.end() );
 | 
			
		||||
            assert(ValidFieldName(F));
 | 
			
		||||
            return std::string{"("} + F + SQLCOMPS[O] + (V ? "true" : "false") + ")" ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline std::string OP(field_name_t F, SqlComparison O , int V) {
 | 
			
		||||
            assert( FieldNames_.find(F) != FieldNames_.end() );
 | 
			
		||||
            assert(ValidFieldName(F));
 | 
			
		||||
            return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline std::string OP(field_name_t F, SqlComparison O , uint64_t V) {
 | 
			
		||||
            assert( FieldNames_.find(F) != FieldNames_.end() );
 | 
			
		||||
            assert(ValidFieldName(F));
 | 
			
		||||
            return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string OP(field_name_t F, SqlComparison O , const std::string & V) {
 | 
			
		||||
            assert( FieldNames_.find(F) != FieldNames_.end() );
 | 
			
		||||
            assert(ValidFieldName(F));
 | 
			
		||||
            return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string OP(field_name_t F, SqlComparison O , const char * V) {
 | 
			
		||||
            assert( FieldNames_.find(F) != FieldNames_.end() );
 | 
			
		||||
            assert(ValidFieldName(F));
 | 
			
		||||
            return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -290,7 +337,7 @@ namespace ORM {
 | 
			
		||||
            return std::string("(")+P1 + BOPS[BOP] + P2 +")";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string OP( bool Paran, const std::string &P1, SqlBinaryOp BOP , const std::string &P2) {
 | 
			
		||||
        std::string OP( [[maybe_unused]] bool  Paran, const std::string &P1, SqlBinaryOp BOP , const std::string &P2) {
 | 
			
		||||
            return P1 + BOPS[BOP] + P2 +")";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -404,7 +451,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        template<typename T> bool GetRecord(field_name_t FieldName, const T & Value,  RecordType & R) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert(ValidFieldName(FieldName));
 | 
			
		||||
 | 
			
		||||
                if(Cache_) {
 | 
			
		||||
                    if(Cache_->GetFromCache(FieldName, Value, R))
 | 
			
		||||
@@ -415,7 +462,7 @@ namespace ORM {
 | 
			
		||||
                Poco::Data::Statement   Select(Session);
 | 
			
		||||
                RecordTuple             RT;
 | 
			
		||||
 | 
			
		||||
                std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" ;
 | 
			
		||||
                std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" + " limit 1";
 | 
			
		||||
 | 
			
		||||
                auto tValue{Value};
 | 
			
		||||
 | 
			
		||||
@@ -424,13 +471,12 @@ namespace ORM {
 | 
			
		||||
                    Poco::Data::Keywords::use(tValue);
 | 
			
		||||
                Select.execute();
 | 
			
		||||
 | 
			
		||||
                if(Select.rowsExtracted()==1) {
 | 
			
		||||
                if(Select.execute()==1) {
 | 
			
		||||
                    Convert(RT,R);
 | 
			
		||||
                    if(Cache_)
 | 
			
		||||
                        Cache_->UpdateCache(R);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            } catch (const Poco::Exception &E) {
 | 
			
		||||
                Logger_.log(E);
 | 
			
		||||
            }
 | 
			
		||||
@@ -443,7 +489,7 @@ namespace ORM {
 | 
			
		||||
                typename T0, typename T1> bool GR(field_name_t FieldName, T & R,T0 &V0, T1 &V1) {
 | 
			
		||||
            try {
 | 
			
		||||
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Select(Session);
 | 
			
		||||
@@ -468,8 +514,10 @@ namespace ORM {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        typedef std::vector<RecordTuple>    RecordList;
 | 
			
		||||
        typedef std::vector<RecordType>     RecordVec;
 | 
			
		||||
        typedef RecordType                  RecordName;
 | 
			
		||||
 | 
			
		||||
        bool GetRecords( uint64_t Offset, uint64_t HowMany, std::vector<RecordType> & Records, const std::string & Where = "", const std::string & OrderBy = "") {
 | 
			
		||||
        bool GetRecords( uint64_t Offset, uint64_t HowMany, RecordVec & Records, const std::string & Where = "", const std::string & OrderBy = "") {
 | 
			
		||||
            try {
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Select(Session);
 | 
			
		||||
@@ -499,7 +547,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        template <typename T> bool UpdateRecord(field_name_t FieldName, const T & Value,  const RecordType & R) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Update(Session);
 | 
			
		||||
@@ -524,6 +572,21 @@ namespace ORM {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool RunStatement(const std::string &St) {
 | 
			
		||||
            try {
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Command(Session);
 | 
			
		||||
 | 
			
		||||
                Command  << St ;
 | 
			
		||||
                Command.execute();
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            } catch (const Poco::Exception &E) {
 | 
			
		||||
                Logger_.log(E);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        template <typename T> bool ReplaceRecord(field_name_t FieldName, const T & Value,  RecordType & R) {
 | 
			
		||||
            try {
 | 
			
		||||
                if(Exists(FieldName, Value)) {
 | 
			
		||||
@@ -538,7 +601,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        template <typename T> bool GetNameAndDescription(field_name_t FieldName, const T & Value, std::string & Name, std::string & Description ) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Select(Session);
 | 
			
		||||
                RecordTuple             RT;
 | 
			
		||||
@@ -565,7 +628,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        template <typename T> bool DeleteRecord(field_name_t FieldName, const T & Value) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
 | 
			
		||||
                Poco::Data::Session     Session = Pool_.get();
 | 
			
		||||
                Poco::Data::Statement   Delete(Session);
 | 
			
		||||
@@ -603,7 +666,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        bool Exists(field_name_t FieldName, const std::string & Value) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
 | 
			
		||||
                RecordType  R;
 | 
			
		||||
                if(GetRecord(FieldName,Value,R))
 | 
			
		||||
@@ -656,7 +719,7 @@ namespace ORM {
 | 
			
		||||
                }
 | 
			
		||||
                if(!ItemList.empty())
 | 
			
		||||
                    ItemList += " , ";
 | 
			
		||||
                auto hint = FieldNames_.find(T[0]);
 | 
			
		||||
                auto hint = FieldNames_.find(Poco::toLower(T[0]));
 | 
			
		||||
                if(hint==FieldNames_.end()) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
@@ -666,9 +729,6 @@ namespace ORM {
 | 
			
		||||
            if(!ItemList.empty()) {
 | 
			
		||||
                OrderByString = " ORDER BY " + ItemList;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::cout << OrderByString << std::endl;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -695,7 +755,7 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        template <typename X> bool ManipulateVectorMember( X T, field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID, bool Add) {
 | 
			
		||||
            try {
 | 
			
		||||
                assert( FieldNames_.find(FieldName) != FieldNames_.end() );
 | 
			
		||||
                assert( ValidFieldName(FieldName) );
 | 
			
		||||
 | 
			
		||||
                RecordType R;
 | 
			
		||||
                if(GetRecord(FieldName, ParentUUID, R)) {
 | 
			
		||||
@@ -729,12 +789,12 @@ namespace ORM {
 | 
			
		||||
                    try {
 | 
			
		||||
                        Command << i, Poco::Data::Keywords::now;
 | 
			
		||||
                    } catch (const Poco::Exception &E) {
 | 
			
		||||
                        Logger_.log(E);
 | 
			
		||||
                        Logger_.error(Poco::format("The following statement '%s' generated an exception during a table upgrade. This maya or may not be a problem.", i));
 | 
			
		||||
                    }
 | 
			
		||||
                        // Logger_.log(E);
 | 
			
		||||
                        // Logger_.error(Poco::format("The following statement '%s' generated an exception during a table upgrade. This may or may not be a problem.", i));
 | 
			
		||||
                        if(!IgnoreExceptions) {
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Command.reset(Session);
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
@@ -809,32 +869,32 @@ namespace ORM {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool AddInUse(field_name_t FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) {
 | 
			
		||||
        inline bool AddConfiguration(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::deviceConfiguration, FieldName, ParentUUID, ChildUUID, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool DelConfiguration(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::deviceConfiguration, FieldName, ParentUUID, ChildUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool AddVariable(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::variables, FieldName, ParentUUID, ChildUUID, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool DelVariable(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::variables, FieldName, ParentUUID, ChildUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool AddInUse(field_name_t FieldName, const std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) {
 | 
			
		||||
            std::string FakeUUID{ Prefix + ":" + ChildUUID};
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool DeleteInUse(field_name_t FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) {
 | 
			
		||||
        inline bool DeleteInUse(field_name_t FieldName, const std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) {
 | 
			
		||||
            std::string FakeUUID{ Prefix + ":" + ChildUUID};
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool DeleteContact(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool AddContact(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool DeleteLocation(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool AddLocation(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) {
 | 
			
		||||
            return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool GetInUse(field_name_t FieldName, const std::string & UUID, std::vector<std::string> & UUIDs ) {
 | 
			
		||||
            RecordType  R;
 | 
			
		||||
            if(GetRecord(FieldName,UUID,R)) {
 | 
			
		||||
@@ -844,6 +904,15 @@ namespace ORM {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool ValidFieldName(const std::string &FieldName) {
 | 
			
		||||
            return FieldNames_.find(Poco::toLower(FieldName)) != FieldNames_.end();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline bool ValidFieldName(const char *FieldName) {
 | 
			
		||||
            std::string Field{FieldName};
 | 
			
		||||
            return ValidFieldName(Field);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
 | 
			
		||||
            if(From<1) From=0;
 | 
			
		||||
            switch(Type_) {
 | 
			
		||||
@@ -860,26 +929,31 @@ namespace ORM {
 | 
			
		||||
 | 
			
		||||
        Poco::Logger & Logger() { return Logger_; }
 | 
			
		||||
 | 
			
		||||
        bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) {
 | 
			
		||||
        inline bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) {
 | 
			
		||||
            if(Cache_)
 | 
			
		||||
                Cache_->Delete(FieldName, Value);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline void GetFieldNames( OpenWifi::Types::StringVec & F) {
 | 
			
		||||
            for(const auto &[field,_]:FieldNames_)
 | 
			
		||||
                F.push_back(field);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        std::string                 TableName_;
 | 
			
		||||
        OpenWifi::DBType            Type_;
 | 
			
		||||
        Poco::Data::SessionPool     &Pool_;
 | 
			
		||||
        Poco::Logger                &Logger_;
 | 
			
		||||
        std::string                 TableName_;
 | 
			
		||||
        std::string                 Prefix_;
 | 
			
		||||
        DBCache<RecordType>         *Cache_= nullptr;
 | 
			
		||||
    private:
 | 
			
		||||
        OpenWifi::DBType            Type_;
 | 
			
		||||
        std::string                 CreateFields_;
 | 
			
		||||
        std::string                 SelectFields_;
 | 
			
		||||
        std::string                 SelectList_;
 | 
			
		||||
        std::string                 UpdateFields_;
 | 
			
		||||
        std::vector<std::string>    IndexCreation_;
 | 
			
		||||
        std::map<std::string,int>   FieldNames_;
 | 
			
		||||
        std::string                 Prefix_;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										509
									
								
								src/framework/ow_constants.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										509
									
								
								src/framework/ow_constants.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,509 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2022-02-21.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include "Poco/String.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wunused-variable"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma clang diagnostic ignored "-Wunused-variable"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::RESTAPI::Errors {
 | 
			
		||||
    struct msg { uint64_t err_num; std::string err_txt; };
 | 
			
		||||
    static const struct msg Error404{404,"Resource does not exist."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg SUCCESS{0,"No error."};
 | 
			
		||||
    static const struct msg PASSWORD_CHANGE_REQUIRED{1,"Password change required"};
 | 
			
		||||
    static const struct msg INVALID_CREDENTIALS{2,"Invalid credentials."};
 | 
			
		||||
    static const struct msg PASSWORD_ALREADY_USED{3,"Password already used."};
 | 
			
		||||
    static const struct msg USERNAME_PENDING_VERIFICATION{4,"Username pending verification."};
 | 
			
		||||
    static const struct msg PASSWORD_INVALID{5,"Password is invalid"};
 | 
			
		||||
    static const struct msg INTERNAL_ERROR{6,"Internal error."};
 | 
			
		||||
    static const struct msg ACCESS_DENIED{7,"Access denied."};
 | 
			
		||||
    static const struct msg INVALID_TOKEN{8,"Invalid token."};
 | 
			
		||||
    static const struct msg EXPIRED_TOKEN{9,"Expired token."};
 | 
			
		||||
    static const struct msg RATE_LIMIT_EXCEEDED{10,"Rate limit exceeded."};
 | 
			
		||||
    static const struct msg BAD_MFA_TRANSACTION{11,"Bad MFA transaction."};
 | 
			
		||||
    static const struct msg MFA_FAILURE{12,"MFA failure."};
 | 
			
		||||
    static const struct msg SECURITY_SERVICE_UNREACHABLE{13,"Security service is unreachable, try again later."};
 | 
			
		||||
    static const struct msg CANNOT_REFRESH_TOKEN{14,"Cannot refresh token."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg MissingUUID{1000,"Missing UUID."};
 | 
			
		||||
    static const struct msg MissingSerialNumber{1001,"Missing Serial Number."};
 | 
			
		||||
    static const struct msg InternalError{1002,"Internal error. Please try later."};
 | 
			
		||||
    static const struct msg InvalidJSONDocument{1003,"Invalid JSON document."};
 | 
			
		||||
    static const struct msg UnsupportedHTTPMethod{1004,"Unsupported HTTP Method"};
 | 
			
		||||
    static const struct msg StillInUse{1005,"Element still in use."};
 | 
			
		||||
    static const struct msg CouldNotBeDeleted{1006,"Element could not be deleted."};
 | 
			
		||||
    static const struct msg NameMustBeSet{1007,"The name property must be set."};
 | 
			
		||||
    static const struct msg ConfigBlockInvalid{1008,"Configuration block type invalid."};
 | 
			
		||||
    static const struct msg UnknownId{1009,"Unknown UUID."};
 | 
			
		||||
    static const struct msg InvalidDeviceTypes{1010,"Unknown or invalid device type(s)."};
 | 
			
		||||
    static const struct msg RecordNotCreated{1011,"Record could not be created."};
 | 
			
		||||
    static const struct msg RecordNotUpdated{1012,"Record could not be updated."};
 | 
			
		||||
    static const struct msg UnknownManagementPolicyUUID{1013,"Unknown management policy UUID."};
 | 
			
		||||
    static const struct msg CannotDeleteRoot{1014,"Root Entity cannot be removed, only modified."};
 | 
			
		||||
    static const struct msg MustCreateRootFirst{1015,"Root entity must be created first."};
 | 
			
		||||
    static const struct msg ParentUUIDMustExist{1016,"Parent UUID must exist."};
 | 
			
		||||
    static const struct msg ConfigurationMustExist{1017,"Configuration must exist."};
 | 
			
		||||
    static const struct msg MissingOrInvalidParameters{1018,"Invalid or missing parameters."};
 | 
			
		||||
    static const struct msg UnknownSerialNumber{1019,"Unknown Serial Number."};
 | 
			
		||||
    static const struct msg InvalidSerialNumber{1020,"Invalid Serial Number."};
 | 
			
		||||
    static const struct msg SerialNumberExists{1021,"Serial Number already exists."};
 | 
			
		||||
    static const struct msg ValidNonRootUUID{1022,"Must be a non-root, and valid UUID."};
 | 
			
		||||
    static const struct msg VenueMustExist{1023,"Venue does not exist."};
 | 
			
		||||
    static const struct msg NotBoth{1024,"You cannot specify both Entity and Venue"};
 | 
			
		||||
    static const struct msg EntityMustExist{1025,"Entity must exist."};
 | 
			
		||||
    static const struct msg ParentOrEntityMustBeSet{1026,"Parent or Entity must be set."};
 | 
			
		||||
    static const struct msg ContactMustExist{1027,"Contact must exist."};
 | 
			
		||||
    static const struct msg LocationMustExist{1028,"Location must exist."};
 | 
			
		||||
    static const struct msg OnlyWSSupported{1029,"This endpoint only supports WebSocket."};
 | 
			
		||||
    static const struct msg SerialNumberMismatch{1030,"Serial Number mismatch."};
 | 
			
		||||
    static const struct msg InvalidCommand{1031,"Invalid command."};
 | 
			
		||||
    static const struct msg NoRecordsDeleted{1032,"No records deleted."};
 | 
			
		||||
    static const struct msg DeviceNotConnected{1033,"Device is not currently connected."};
 | 
			
		||||
    static const struct msg CannotCreateWS{1034,"Telemetry system could not create WS endpoint. Please try again."};
 | 
			
		||||
    static const struct msg BothDeviceTypeRevision{1035,"Both deviceType and revision must be set."};
 | 
			
		||||
    static const struct msg IdOrSerialEmpty{1036,"SerialNumber and Id must not be empty."};
 | 
			
		||||
    static const struct msg MissingUserID{1037,"Missing user ID."};
 | 
			
		||||
    static const struct msg IdMustBe0{1038,"To create a user, you must set the ID to 0"};
 | 
			
		||||
    static const struct msg InvalidUserRole{1039,"Invalid userRole."};
 | 
			
		||||
    static const struct msg InvalidEmailAddress{1040,"Invalid email address."};
 | 
			
		||||
    static const struct msg PasswordRejected{1041,"Password was rejected. This maybe an old password."};
 | 
			
		||||
    static const struct msg InvalidIPRanges{1042,"Invalid IP range specifications."};
 | 
			
		||||
    static const struct msg InvalidLOrderBy{1043,"Invalid orderBy specification."};
 | 
			
		||||
    static const struct msg NeedMobileNumber{1044,"You must provide at least one validated phone number."};
 | 
			
		||||
    static const struct msg BadMFAMethod{1045,"MFA only supports sms or email."};
 | 
			
		||||
    static const struct msg InvalidCredentials{1046,"Invalid credentials (username/password)."};
 | 
			
		||||
    static const struct msg InvalidPassword{1047,"Password does not conform to basic password rules."};
 | 
			
		||||
    static const struct msg UserPendingVerification{1048,"User access denied pending email verification."};
 | 
			
		||||
    static const struct msg PasswordMustBeChanged{1049,"Password must be changed."};
 | 
			
		||||
    static const struct msg UnrecognizedRequest{1050,"Ill-formed request. Please consult documentation."};
 | 
			
		||||
    static const struct msg MissingAuthenticationInformation{1051,"Missing authentication information."};
 | 
			
		||||
    static const struct msg InsufficientAccessRights{1052,"Insufficient access rights to complete the operation."};
 | 
			
		||||
    static const struct msg ExpiredToken{1053,"Token has expired, user must login."};
 | 
			
		||||
    static const struct msg SubscriberMustExist{1054,"Subscriber must exist."};
 | 
			
		||||
    static const struct msg AuthenticatorVerificationIncomplete{1055,"Authenticator validation is not complete."};
 | 
			
		||||
    static const struct msg SMSCouldNotBeSentRetry{1056,"SMS could not be sent to validate device, try later or change the phone number."};
 | 
			
		||||
    static const struct msg SMSCouldNotValidate{1057,"Code and number could not be validated"};
 | 
			
		||||
    static const struct msg InvalidDeviceClass{1058,"Invalid device class. Must be: any, venue, entity, or subscriber"};
 | 
			
		||||
    static const struct msg SerialNumberAlreadyProvisioned{1059,"This device has already been provisioned to a subscriber."};
 | 
			
		||||
    static const struct msg SerialNumberNotTheProperClass{1060,"Device is not available to subscribers. It ahs been assigned to another class of devices."};
 | 
			
		||||
    static const struct msg UserAlreadyExists{1061,"Username already exists."};
 | 
			
		||||
    static const struct msg NotImplemented{1062,"Function not implemented."};
 | 
			
		||||
    static const struct msg VariableMustExist{1063,"Specified variable does not exist."};
 | 
			
		||||
    static const struct msg InvalidEntityType{1064,"Invalid entity type."};
 | 
			
		||||
    static const struct msg CannotDeleteSubEntity{1065,"Cannot delete the default subscriber entity."};
 | 
			
		||||
    static const struct msg OperatorIdMustExist{1066,"Missing or bad Operator ID"};
 | 
			
		||||
    static const struct msg CannotDeleteDefaultOperator{1067,"Cannot delete the default operator."};
 | 
			
		||||
    static const struct msg CannotCreateDefaultOperator{1068,"Cannot create the default operator."};
 | 
			
		||||
    static const struct msg InvalidRRM{1069,"Invalid RRM value."};
 | 
			
		||||
    static const struct msg InvalidIPAddresses{1070,"Invalid IP addresses."};
 | 
			
		||||
    static const struct msg InvalidBillingCode{1071,"Empty of invalid billing code."};
 | 
			
		||||
    static const struct msg InvalidBillingPeriod{1072,"Invalid billing period."};
 | 
			
		||||
    static const struct msg InvalidSubscriberId{1073,"Invalid subscriber ID."};
 | 
			
		||||
    static const struct msg InvalidContactId{1074,"Invalid contact ID."};
 | 
			
		||||
    static const struct msg InvalidLocationId{1075,"Invalid location ID."};
 | 
			
		||||
    static const struct msg InvalidContactType{1076,"Invalid contact type."};
 | 
			
		||||
    static const struct msg InvalidLocationType{1077,"Invalid location type."};
 | 
			
		||||
    static const struct msg InvalidOperatorId{1078,"Invalid operator ID."};
 | 
			
		||||
    static const struct msg InvalidServiceClassId{1079,"Invalid service class ID."};
 | 
			
		||||
    static const struct msg InvalidSubscriberDeviceId{1080,"Invalid subscriber device ID."};
 | 
			
		||||
    static const struct msg InvalidRegistrationOperatorId{1081,"Invalid registration operator ID."};
 | 
			
		||||
    static const struct msg InvalidRegistrationOperatorName{1082,"Invalid registration operator name."};
 | 
			
		||||
    static const struct msg RegistrationNameDuplicate{1083,"Registration name must be unique."};
 | 
			
		||||
    static const struct msg SMSMFANotEnabled{1084,"SMS is not enabled in the security service."};
 | 
			
		||||
    static const struct msg EMailMFANotEnabled{1085,"email is not enabled in the security service."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg TOTInvalidCode{1086,"Invalid code."};
 | 
			
		||||
    static const struct msg TOTInvalidIndex{1087,"Invalid index."};
 | 
			
		||||
    static const struct msg TOTRepeatedCode{1088,"Code is repeated. Must be new code."};
 | 
			
		||||
    static const struct msg TOTInvalidProtocol{1089,"Invalid protocol sequence."};
 | 
			
		||||
    static const struct msg TOTNoSession{1090,"No validation session present."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg SignupAlreadySigned{1091,"Code is repeated. Must be new code."};
 | 
			
		||||
    static const struct msg SignupEmailCheck{1092,"Waiting for email check completion."};
 | 
			
		||||
    static const struct msg SignupWaitingForDevice{1093,"Waiting for device."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg SMSMissingPhoneNumber{1094,"Missing phone number"};
 | 
			
		||||
    static const struct msg SMSTryLater{1095,"SMS could not be sent. Verify the number or try again later."};
 | 
			
		||||
    static const struct msg SMSMissingChallenge{1096,"Missing 'challengeCode'"};
 | 
			
		||||
	static const struct msg MustHaveConfigElement{1097,"Must have 'configuration' element."};
 | 
			
		||||
 | 
			
		||||
	static const struct msg ModelIDListCannotBeEmpty{1098,"Model ID list cannot be empty."};
 | 
			
		||||
	static const struct msg DefConfigNameExists{1099,"Configuration name already exists."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg SubNoDeviceActivated{1100,"No devices activated yet."};
 | 
			
		||||
    static const struct msg SubConfigNotRefreshed{1101,"Configuration could not be refreshed."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg ProvServiceNotAvailable{1102,"Provisioning service not available yet."};
 | 
			
		||||
    static const struct msg SSIDInvalidPassword{1103,"Invalid password length. Must be 8 characters or greater, and a maximum of 32 characters."};
 | 
			
		||||
    static const struct msg InvalidStartingIPAddress{1104,"Invalid starting/ending IP address."};
 | 
			
		||||
    static const struct msg SubnetFormatError{1105,"Subnet must be in format like 192.168.1.1/24."};
 | 
			
		||||
    static const struct msg DeviceModeError{1106,"Device mode subnet must be of the form 192.168.1.1/24."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg BadDeviceMode{1107,"Mode must be bridge, nat, or manual."};
 | 
			
		||||
    static const struct msg DefaultGatewayFormat{1108,"Default gateway must be in format like 192.168.1.1."};
 | 
			
		||||
    static const struct msg PrimaryDNSFormat{1109,"Primary DNS must be an IP address i.e. 192.168.1.1."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg SecondaryDNSFormat{1110,"Secondary DNS must be an IP address i.e. 192.168.1.1."};
 | 
			
		||||
    static const struct msg BadConnectionType{1111,"Internet Connection must be automatic, bridge, pppoe, or manual."};
 | 
			
		||||
    static const struct msg InvalidDeviceID{1112,"Invalid deviceID."};
 | 
			
		||||
    static const struct msg InvalidVisibilityAttribute{1113,"Invalid visibility attribute."};
 | 
			
		||||
    static const struct msg UnknownConfigurationSection{1114,"Unknown section."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg CannotValidatePhoneNumber{1115,"Phone number could not be validated."};
 | 
			
		||||
    static const struct msg RootUsersNoOwners{1116,"ROOT users may not have owners."};
 | 
			
		||||
    static const struct msg PartnerMustHaveEntity{1118,"Partner user must belong to an entity."};
 | 
			
		||||
    static const struct msg RootCannotModifyUsers{1119,"ROOT may not modify user roles."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg CertificateNotIssued{1120,"Certificate was not issued."};
 | 
			
		||||
    static const struct msg IncompleteCertificate{1121,"Incomplete certificate information. Cannot be downloaded. You must delete and recreate."};
 | 
			
		||||
    static const struct msg InvalidCertificateType{1122,"Invalid certificate type."};
 | 
			
		||||
    static const struct msg InvalidDeviceName{1123,"Invalid device name."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg InvalidRedirectorName{1124,"Invalid redirector name"};
 | 
			
		||||
    static const struct msg CommonNameAlreadyExists{1125,"A device/server of this name already exists"};
 | 
			
		||||
    static const struct msg CertificateAlreadyExists{1126,"A certificate for this device already exists."};
 | 
			
		||||
    static const struct msg CannotCreateCertTryAgain{1127,"Device certificate could not be created. Please try later."};
 | 
			
		||||
    static const struct msg CouldNotRevoke{1128,"Certificate could not be revoked."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg CouldNotModifyCert{1129,"Certificate could not me modified. Please verify the information you supplied."};
 | 
			
		||||
    static const struct msg BatchCertNoCreated{1130,"Certificates have not been created for this batch."};
 | 
			
		||||
    static const struct msg BatchTooBig{1131,"Illegal number of MAC Addresses: must be between 1 and 1000."};
 | 
			
		||||
 | 
			
		||||
    static const struct msg OutstandingJobs{1132,"Batch has running outstanding jobs. Please wait until job is finished."};
 | 
			
		||||
    static const struct msg InvalidSMSNotificationList{1133,"Invalid SMS Notification list."};
 | 
			
		||||
    static const struct msg InvalidEMailNotificationList{1134,"Invalid email Notification list."};
 | 
			
		||||
    static const struct msg CannotChangeCommanNames{1135,"You cannot provide new/modified common names after jobs have been run for a batch."};
 | 
			
		||||
    static const struct msg FailedToVerifyDigicert{1136,"Failed to verify the DigiCert information provided."};
 | 
			
		||||
    static const struct msg CouldNotPerformCommand{1137,"Could not perform command."};
 | 
			
		||||
 | 
			
		||||
	static const struct msg PoolNameInvalid{1138,"Pool name is invalid."};
 | 
			
		||||
	static const struct msg InvalidRadiusProxyStrategy{1139,"Strategy name must be: random, round_robin, weighted."};
 | 
			
		||||
	static const struct msg InvalidRadiusProxyMonitorMethod{1140,"monitorMethod must be: none, https, radius."};
 | 
			
		||||
	static const struct msg MustHaveAtLeastOneRadiusServer{1141,"Must have at least one RADIUS server."};
 | 
			
		||||
	static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."};
 | 
			
		||||
	static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::RESTAPI::Protocol {
 | 
			
		||||
	static const char * CAPABILITIES = "capabilities";
 | 
			
		||||
	static const char * LOGS = "logs";
 | 
			
		||||
	static const char * HEALTHCHECKS = "healthchecks";
 | 
			
		||||
	static const char * STATISTICS = "statistics";
 | 
			
		||||
	static const char * STATUS = "status";
 | 
			
		||||
	static const char * SERIALNUMBER = "serialNumber";
 | 
			
		||||
	static const char * PERFORM = "perform";
 | 
			
		||||
	static const char * CONFIGURE = "configure";
 | 
			
		||||
	static const char * UPGRADE = "upgrade";
 | 
			
		||||
	static const char * REBOOT = "reboot";
 | 
			
		||||
	static const char * FACTORY = "factory";
 | 
			
		||||
	static const char * LEDS = "leds";
 | 
			
		||||
	static const char * TRACE = "trace";
 | 
			
		||||
	static const char * REQUEST = "request";
 | 
			
		||||
	static const char * WIFISCAN = "wifiscan";
 | 
			
		||||
	static const char * EVENTQUEUE = "eventqueue";
 | 
			
		||||
	static const char * RTTY = "rtty";
 | 
			
		||||
	static const char * COMMAND = "command";
 | 
			
		||||
	static const char * STARTDATE = "startDate";
 | 
			
		||||
	static const char * ENDDATE = "endDate";
 | 
			
		||||
	static const char * OFFSET = "offset";
 | 
			
		||||
	static const char * LIMIT = "limit";
 | 
			
		||||
	static const char * LIFETIME = "lifetime";
 | 
			
		||||
	static const char * UUID = "UUID";
 | 
			
		||||
	static const char * DATA = "data";
 | 
			
		||||
	static const char * CONFIGURATION = "configuration";
 | 
			
		||||
	static const char * WHEN = "when";
 | 
			
		||||
	static const char * URI = "uri";
 | 
			
		||||
	static const char * LOGTYPE = "logType";
 | 
			
		||||
	static const char * VALUES = "values";
 | 
			
		||||
	static const char * TYPES = "types";
 | 
			
		||||
	static const char * PAYLOAD = "payload";
 | 
			
		||||
	static const char * KEEPREDIRECTOR = "keepRedirector";
 | 
			
		||||
	static const char * NETWORK = "network";
 | 
			
		||||
	static const char * INTERFACE = "interface";
 | 
			
		||||
	static const char * BANDS = "bands";
 | 
			
		||||
	static const char * CHANNELS = "channels";
 | 
			
		||||
	static const char * VERBOSE = "verbose";
 | 
			
		||||
	static const char * MESSAGE = "message";
 | 
			
		||||
	static const char * STATE = "state";
 | 
			
		||||
	static const char * HEALTHCHECK = "healthcheck";
 | 
			
		||||
	static const char * PCAP_FILE_TYPE = "pcap";
 | 
			
		||||
	static const char * DURATION = "duration";
 | 
			
		||||
	static const char * NUMBEROFPACKETS = "numberOfPackets";
 | 
			
		||||
	static const char * FILTER = "filter";
 | 
			
		||||
	static const char * SELECT = "select";
 | 
			
		||||
	static const char * SERIALONLY = "serialOnly";
 | 
			
		||||
	static const char * COUNTONLY = "countOnly";
 | 
			
		||||
	static const char * DEVICEWITHSTATUS = "deviceWithStatus";
 | 
			
		||||
	static const char * DEVICESWITHSTATUS = "devicesWithStatus";
 | 
			
		||||
	static const char * DEVICES = "devices";
 | 
			
		||||
	static const char * COUNT = "count";
 | 
			
		||||
	static const char * SERIALNUMBERS = "serialNumbers";
 | 
			
		||||
	static const char * CONFIGURATIONS = "configurations";
 | 
			
		||||
	static const char * NAME = "name";
 | 
			
		||||
	static const char * COMMANDS = "commands";
 | 
			
		||||
	static const char * COMMANDUUID = "commandUUID";
 | 
			
		||||
	static const char * FIRMWARES = "firmwares";
 | 
			
		||||
	static const char * TOPIC = "topic";
 | 
			
		||||
	static const char * HOST = "host";
 | 
			
		||||
	static const char * OS = "os";
 | 
			
		||||
	static const char * HOSTNAME = "hostname";
 | 
			
		||||
	static const char * PROCESSORS = "processors";
 | 
			
		||||
	static const char * REASON = "reason";
 | 
			
		||||
	static const char * RELOAD = "reload";
 | 
			
		||||
	static const char * SUBSYSTEMS = "subsystems";
 | 
			
		||||
	static const char * FILEUUID = "uuid";
 | 
			
		||||
	static const char * USERID = "userId";
 | 
			
		||||
	static const char * PASSWORD = "password";
 | 
			
		||||
	static const char * TOKEN = "token";
 | 
			
		||||
	static const char * SETLOGLEVEL = "setloglevel";
 | 
			
		||||
	static const char * GETLOGLEVELS = "getloglevels";
 | 
			
		||||
	static const char * GETSUBSYSTEMNAMES = "getsubsystemnames";
 | 
			
		||||
	static const char * GETLOGLEVELNAMES = "getloglevelnames";
 | 
			
		||||
	static const char * STATS = "stats";
 | 
			
		||||
	static const char * PING = "ping";
 | 
			
		||||
	static const char * PARAMETERS = "parameters";
 | 
			
		||||
	static const char * VALUE = "value";
 | 
			
		||||
	static const char * LASTONLY = "lastOnly";
 | 
			
		||||
	static const char * NEWEST = "newest";
 | 
			
		||||
	static const char * ACTIVESCAN = "activeScan";
 | 
			
		||||
	static const char * OVERRIDEDFS = "override_dfs";
 | 
			
		||||
	static const char * LIST = "list";
 | 
			
		||||
	static const char * TAG = "tag";
 | 
			
		||||
	static const char * TAGLIST = "tagList";
 | 
			
		||||
	static const char * DESCRIPTION = "description";
 | 
			
		||||
	static const char * NOTES = "notes";
 | 
			
		||||
	static const char * DEVICETYPE = "deviceType";
 | 
			
		||||
	static const char * REVISION = "revision";
 | 
			
		||||
	static const char * AGES = "ages";
 | 
			
		||||
	static const char * REVISIONS = "revisions";
 | 
			
		||||
	static const char * DEVICETYPES = "deviceTypes";
 | 
			
		||||
	static const char * LATESTONLY = "latestOnly";
 | 
			
		||||
	static const char * IDONLY = "idOnly";
 | 
			
		||||
	static const char * REVISIONSET = "revisionSet";
 | 
			
		||||
	static const char * DEVICESET = "deviceSet";
 | 
			
		||||
	static const char * HISTORY = "history";
 | 
			
		||||
	static const char * ID = "id";
 | 
			
		||||
	static const char * VERSION = "version";
 | 
			
		||||
	static const char * TIMES = "times";
 | 
			
		||||
	static const char * UPTIME = "uptime";
 | 
			
		||||
	static const char * START = "start";
 | 
			
		||||
	static const char * DEBUG = "debug";
 | 
			
		||||
	static const char * SCRIPT = "script";
 | 
			
		||||
	static const char * TIMEOUT = "timeout";
 | 
			
		||||
 | 
			
		||||
	static const char * NEWPASSWORD = "newPassword";
 | 
			
		||||
	static const char * USERS = "users";
 | 
			
		||||
	static const char * WITHEXTENDEDINFO = "withExtendedInfo";
 | 
			
		||||
 | 
			
		||||
	static const char * ERRORTEXT = "errorText";
 | 
			
		||||
	static const char * ERRORCODE = "errorCode";
 | 
			
		||||
	static const char * AVATARID = "avatarId";
 | 
			
		||||
	static const char * UNNAMED = "(unnamed)";
 | 
			
		||||
	static const char * UNSPECIFIED = "(unspecified)";
 | 
			
		||||
	static const char * CONTENTDISPOSITION = "Content-Disposition";
 | 
			
		||||
	static const char * CONTENTTYPE = "Content-Type";
 | 
			
		||||
 | 
			
		||||
	static const char * REQUIREMENTS = "requirements";
 | 
			
		||||
	static const char * PASSWORDPATTERN = "passwordPattern";
 | 
			
		||||
	static const char * ACCESSPOLICY = "accessPolicy";
 | 
			
		||||
	static const char * PASSWORDPOLICY = "passwordPolicy";
 | 
			
		||||
	static const char * FORGOTPASSWORD = "forgotPassword";
 | 
			
		||||
	static const char * RESENDMFACODE = "resendMFACode";
 | 
			
		||||
	static const char * COMPLETEMFACHALLENGE = "completeMFAChallenge";
 | 
			
		||||
	static const char * ME = "me";
 | 
			
		||||
	static const char * TELEMETRY = "telemetry";
 | 
			
		||||
	static const char * INTERVAL = "interval";
 | 
			
		||||
	static const char * UI = "UI";
 | 
			
		||||
	static const char * BANDWIDTH = "bandwidth";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::uCentralProtocol {
 | 
			
		||||
 | 
			
		||||
    const int SERIAL_NUMBER_LENGTH = 30;
 | 
			
		||||
 | 
			
		||||
    // vocabulary used in the PROTOCOL.md file
 | 
			
		||||
    static const char *JSONRPC = "jsonrpc";
 | 
			
		||||
    static const char *ID = "id";
 | 
			
		||||
    static const char *UUID = "uuid";
 | 
			
		||||
    static const char *JSONRPC_VERSION = "2.0";
 | 
			
		||||
    static const char *METHOD = "method";
 | 
			
		||||
    static const char *PARAMS = "params";
 | 
			
		||||
    static const char *SERIAL = "serial";
 | 
			
		||||
    static const char *FIRMWARE = "firmware";
 | 
			
		||||
    static const char *CONNECT = "connect";
 | 
			
		||||
    static const char *STATE = "state";
 | 
			
		||||
    static const char *STATUS = "status";
 | 
			
		||||
    static const char *ERROR = "error";
 | 
			
		||||
    static const char *TEXT = "text";
 | 
			
		||||
    static const char *HEALTHCHECK = "healthcheck";
 | 
			
		||||
    static const char *LOG = "log";
 | 
			
		||||
    static const char *CRASHLOG = "crashlog";
 | 
			
		||||
    static const char *PING = "ping";
 | 
			
		||||
    static const char *CFGPENDING = "cfgpending";
 | 
			
		||||
    static const char *RECOVERY = "recovery";
 | 
			
		||||
    static const char *COMPRESS_64 = "compress_64";
 | 
			
		||||
    static const char *CAPABILITIES = "capabilities";
 | 
			
		||||
    static const char *REQUEST_UUID = "request_uuid";
 | 
			
		||||
    static const char *SANITY = "sanity";
 | 
			
		||||
    static const char *DATA = "data";
 | 
			
		||||
    static const char *LOGLINES = "loglines";
 | 
			
		||||
    static const char *SEVERITY = "severity";
 | 
			
		||||
    static const char *ACTIVE = "active";
 | 
			
		||||
    static const char *OVERRIDEDFS = "override_dfs";
 | 
			
		||||
    static const char *REBOOT = "reboot";
 | 
			
		||||
    static const char *WHEN = "when";
 | 
			
		||||
    static const char *CONFIG = "config";
 | 
			
		||||
    static const char *EMPTY_JSON_DOC = "{}";
 | 
			
		||||
    static const char *RESULT = "result";
 | 
			
		||||
	static const char *RESULT_64 = "result_64";
 | 
			
		||||
	static const char *RESULT_SZ = "result_sz";
 | 
			
		||||
    static const char *REQUEST = "request";
 | 
			
		||||
    static const char *PERFORM = "perform";
 | 
			
		||||
    static const char *CONFIGURE = "configure";
 | 
			
		||||
    static const char *PENDING = "pending";
 | 
			
		||||
    static const char *SUBMITTED_BY_SYSTEM = "*system";
 | 
			
		||||
    static const char *URI = "uri";
 | 
			
		||||
    static const char *COMMAND = "command";
 | 
			
		||||
    static const char *PAYLOAD = "payload";
 | 
			
		||||
    static const char *KEEP_REDIRECTOR = "keep_redirector";
 | 
			
		||||
    static const char *DURATION = "duration";
 | 
			
		||||
    static const char *PATTERN = "pattern";
 | 
			
		||||
    static const char *LEDS = "leds";
 | 
			
		||||
	static const char *DEBUG = "debug";
 | 
			
		||||
    static const char *ON = "on";
 | 
			
		||||
    static const char *OFF = "off";
 | 
			
		||||
    static const char *BLINK = "blink";
 | 
			
		||||
    static const char *PACKETS = "packets";
 | 
			
		||||
    static const char *NETWORK = "network";
 | 
			
		||||
    static const char *INTERFACE = "interface";
 | 
			
		||||
    static const char *TRACE = "trace";
 | 
			
		||||
    static const char *WIFISCAN = "wifiscan";
 | 
			
		||||
    static const char *TYPES = "types";
 | 
			
		||||
    static const char *EVENT = "event";
 | 
			
		||||
    static const char *MESSAGE = "message";
 | 
			
		||||
    static const char *RTTY = "rtty";
 | 
			
		||||
    static const char *TOKEN = "token";
 | 
			
		||||
    static const char *SERVER = "server";
 | 
			
		||||
    static const char *PORT = "port";
 | 
			
		||||
    static const char *USER = "user";
 | 
			
		||||
    static const char *TIMEOUT = "timeout";
 | 
			
		||||
    static const char *UPGRADE = "upgrade";
 | 
			
		||||
    static const char *FACTORY = "factory";
 | 
			
		||||
    static const char *VERBOSE = "verbose";
 | 
			
		||||
    static const char *BANDS = "bands";
 | 
			
		||||
    static const char *CHANNELS = "channels";
 | 
			
		||||
    static const char *PASSWORD = "password";
 | 
			
		||||
    static const char *DEVICEUPDATE = "deviceupdate";
 | 
			
		||||
 | 
			
		||||
    static const char *SERIALNUMBER = "serialNumber";
 | 
			
		||||
    static const char *COMPATIBLE = "compatible";
 | 
			
		||||
    static const char *DISCONNECTION = "disconnection";
 | 
			
		||||
    static const char *TIMESTAMP = "timestamp";
 | 
			
		||||
    static const char *SYSTEM = "system";
 | 
			
		||||
    static const char *HOST = "host";
 | 
			
		||||
    static const char *CONNECTIONIP = "connectionIp";
 | 
			
		||||
    static const char *TELEMETRY = "telemetry";
 | 
			
		||||
    static const char *BANDWIDTH = "bandwidth";
 | 
			
		||||
 | 
			
		||||
	static const char *SCRIPT = "script";
 | 
			
		||||
	static const char *TYPE = "type";
 | 
			
		||||
 | 
			
		||||
	static const char *RADIUS = "radius";
 | 
			
		||||
	static const char *RADIUSDATA = "data";
 | 
			
		||||
	static const char *RADIUSACCT = "acct";
 | 
			
		||||
	static const char *RADIUSAUTH = "auth";
 | 
			
		||||
	static const char *RADIUSDST = "dst";
 | 
			
		||||
	static const char *IES = "ies";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::uCentralProtocol::Events {
 | 
			
		||||
 | 
			
		||||
    static const char *CONNECT = "connect";
 | 
			
		||||
    static const char *STATE = "state";
 | 
			
		||||
    static const char *HEALTHCHECK = "healthcheck";
 | 
			
		||||
    static const char *LOG = "log";
 | 
			
		||||
    static const char *CRASHLOG = "crashlog";
 | 
			
		||||
    static const char *PING = "ping";
 | 
			
		||||
    static const char *CFGPENDING = "cfgpending";
 | 
			
		||||
    static const char *RECOVERY = "recovery";
 | 
			
		||||
    static const char *TELEMETRY = "telemetry";
 | 
			
		||||
    static const char *DEVICEUPDATE = "deviceupdate";
 | 
			
		||||
 | 
			
		||||
    enum EVENT_MSG {
 | 
			
		||||
		ET_UNKNOWN,
 | 
			
		||||
		ET_CONNECT,
 | 
			
		||||
		ET_STATE,
 | 
			
		||||
		ET_HEALTHCHECK,
 | 
			
		||||
		ET_LOG,
 | 
			
		||||
		ET_CRASHLOG,
 | 
			
		||||
		ET_PING,
 | 
			
		||||
		ET_CFGPENDING,
 | 
			
		||||
		ET_RECOVERY,
 | 
			
		||||
		ET_DEVICEUPDATE,
 | 
			
		||||
		ET_TELEMETRY
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline EVENT_MSG EventFromString(const std::string & Method) {
 | 
			
		||||
		if(strcmp(STATE,Method.c_str())==0)
 | 
			
		||||
			return ET_STATE;
 | 
			
		||||
		else if(strcmp(HEALTHCHECK,Method.c_str())==0)
 | 
			
		||||
			return ET_HEALTHCHECK;
 | 
			
		||||
		else if(strcmp(CONNECT,Method.c_str())==0)
 | 
			
		||||
			return ET_CONNECT;
 | 
			
		||||
		else if(strcmp(CFGPENDING,Method.c_str())==0)
 | 
			
		||||
			return ET_CFGPENDING;
 | 
			
		||||
		else if(strcmp(CRASHLOG,Method.c_str())==0)
 | 
			
		||||
			return ET_CRASHLOG;
 | 
			
		||||
		else if(strcmp(DEVICEUPDATE,Method.c_str())==0)
 | 
			
		||||
			return ET_DEVICEUPDATE;
 | 
			
		||||
		else if(strcmp(LOG,Method.c_str())==0)
 | 
			
		||||
			return ET_LOG;
 | 
			
		||||
		else if(strcmp(PING,Method.c_str())==0)
 | 
			
		||||
			return ET_PING;
 | 
			
		||||
		else if(strcmp(RECOVERY,Method.c_str())==0)
 | 
			
		||||
			return ET_RECOVERY;
 | 
			
		||||
		else if(strcmp(TELEMETRY,Method.c_str())==0)
 | 
			
		||||
			return ET_TELEMETRY;
 | 
			
		||||
		return ET_UNKNOWN;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::Provisioning::DeviceClass {
 | 
			
		||||
 | 
			
		||||
    static const char * ANY = "any";
 | 
			
		||||
    static const char * SUBSCRIBER = "subscriber";
 | 
			
		||||
    static const char * VENUE = "venue";
 | 
			
		||||
    static const char * ENTITY = "entity";
 | 
			
		||||
 | 
			
		||||
    inline bool Validate(const char *s) {
 | 
			
		||||
        static std::vector<std::string> Values{ ANY, ENTITY, SUBSCRIBER, VENUE };
 | 
			
		||||
        return std::find(cbegin(Values), cend(Values), s) != cend(Values);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__ )
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user