mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 02:37:56 +00:00 
			
		
		
		
	Compare commits
	
		
			445 Commits
		
	
	
		
			feature/te
			...
			v2.6.0-RC3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 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 | ||
|   | 2fb80c68dd | ||
|   | 0652c13139 | ||
|   | feb5ff1f2c | ||
|   | 5a9a62ff7e | ||
|   | bd331913e1 | ||
|   | 5756e31ae6 | ||
|   | 884b91af63 | ||
|   | fed43efadf | ||
|   | 48d3e56b79 | ||
|   | a0f9abea88 | ||
|   | 3e0ecda9d6 | ||
|   | ad38d8e84c | ||
|   | 27c581750c | ||
|   | e09ee35940 | ||
|   | 3c4d9612d3 | ||
|   | 6485b2426c | ||
|   | 3d3dbc6b4d | ||
|   | 8965b3c590 | ||
|   | 77941c4775 | ||
|   | ef9cd80df6 | ||
|   | 042f7619ec | ||
|   | 8a371d7eaf | ||
|   | ac92c7da85 | ||
|   | 7a8449efbf | ||
|   | 8365aa5463 | ||
|   | 1c4f961971 | ||
|   | 19c92edfcc | ||
|   | 3fd6e6b849 | ||
|   | bc6d8a8a79 | ||
|   | 29da9b4b8e | ||
|   | b3f1f35bb4 | ||
|   | a9bd44b3b2 | ||
|   | 01f457dd0c | ||
|   | f27f036e62 | ||
|   | 27f8d06cab | ||
|   | 7960cda46e | ||
|   | 9907f91c49 | ||
|   | b3b98d90ca | ||
|   | ef947c3e33 | ||
|   | a5eb0d792b | ||
|   | 151585f6e5 | ||
|   | 7fc7daf595 | ||
|   | ebe2df4dc7 | ||
|   | 9dcc19f4fe | ||
|   | 984ba88341 | ||
|   | b14eba63c3 | ||
|   | b8c02906ea | ||
|   | f3c3539f62 | ||
|   | 5fef83d726 | ||
|   | 874e28ffff | ||
|   | f84b8c4b5c | ||
|   | ae6a986e57 | ||
|   | 04cffd13c8 | ||
|   | 28635dcbdd | ||
|   | 6a67bf80af | ||
|   | 9460cc1e5b | ||
|   | 6d20c8408f | ||
|   | fd21917a93 | ||
|   | c47e9bc98d | ||
|   | 30431ab954 | ||
|   | 76175d8bbb | ||
|   | 36e16e3c8e | ||
|   | cc4e5848a5 | ||
|   | 8425950da7 | ||
|   | cf903a57ab | ||
|   | d38e4ca2fc | ||
|   | 584254cb07 | ||
|   | dcf7ff5f48 | ||
|   | 1039a53925 | ||
|   | a80bcd16d8 | ||
|   | fce18f6238 | ||
|   | f8c6dad974 | ||
|   | eec8662a3c | ||
|   | f26c6e1454 | ||
|   | 08a50db13c | ||
|   | 7b741048ff | ||
|   | 7fcd451e3b | ||
|   | c545be6ae9 | ||
|   | b1f489bf4f | ||
|   | 92910fe0c5 | ||
|   | eda30b3dc3 | ||
|   | 51dd7bdfa7 | ||
|   | 2eccf1ef06 | ||
|   | b37edca02c | ||
|   | e831619673 | ||
|   | 78ae79b1d5 | ||
|   | 2bc6d7c325 | ||
|   | 0f6a95a330 | ||
|   | 83a1d80d77 | ||
|   | 84bcb28328 | ||
|   | 4d03faf523 | ||
|   | 73096153b4 | ||
|   | 1cf9894f7d | ||
|   | f54cd95fc4 | ||
|   | 882226ccdb | ||
|   | e5f10ccd17 | ||
|   | c500ae36b1 | ||
|   | 6ead810ec6 | ||
|   | c6ac384cdb | ||
|   | f28e07a615 | ||
|   | c7c5401bc2 | ||
|   | 6264c7f3bb | ||
|   | c078bdb555 | ||
|   | 81131b8038 | ||
|   | 4633db416d | ||
|   | 6c14337333 | ||
|   | 784fc3256b | ||
|   | 2c513d8374 | ||
|   | d202b9e365 | ||
|   | b869da3b09 | ||
|   | f31195e854 | ||
|   | ec4ab520d8 | ||
|   | a9ade83094 | ||
|   | 977742d802 | ||
|   | b69b90b243 | ||
|   | ec0aa4e15a | ||
|   | 5fc313aa50 | ||
|   | a3975829e4 | ||
|   | e8cf7a6f21 | ||
|   | d27441d793 | ||
|   | ae5c32a8ec | ||
|   | 96c684fe5e | ||
|   | 8609990551 | ||
|   | 4566bb942c | ||
|   | e5d6f42433 | ||
|   | 524f79e825 | ||
|   | be46b46340 | ||
|   | 5ff0841112 | ||
|   | a6c115adb5 | ||
|   | 4d474fe92c | ||
|   | 4b46e0c9c9 | ||
|   | de0ddc769b | ||
|   | 4a11602fb9 | ||
|   | ef1f7098a6 | ||
|   | 38eebe6162 | ||
|   | 5124ed016c | ||
|   | fb632b6ce1 | ||
|   | 775d0c0a65 | ||
|   | fb2ddaa136 | ||
|   | f51e00c50c | ||
|   | da49bebb15 | ||
|   | 916d5cdf13 | ||
|   | 5eecfbfd30 | ||
|   | 32a5c81f1d | ||
|   | a72189f854 | ||
|   | 2be40d5d17 | ||
|   | f8407f7b7c | ||
|   | 2ec792a74b | ||
|   | 72f0b11f81 | ||
|   | 00965b78c7 | ||
|   | b2c06affa8 | ||
|   | 7b467850b6 | ||
|   | be89574363 | ||
|   | e4d3855251 | ||
|   | 57bd712634 | ||
|   | 797f4e9c80 | ||
|   | 309a856cd0 | ||
|   | 937a20beea | ||
|   | 2217a428c1 | ||
|   | ec82bdec24 | ||
|   | 40faa84d2b | ||
|   | cb3efcecb5 | ||
|   | e11d955529 | ||
|   | 5a4eafee7d | ||
|   | 2df45c26a4 | ||
|   | 311786f8d8 | ||
|   | 829de62967 | ||
|   | 55d1f9571d | ||
|   | 80a520c4cc | ||
|   | 040623fc8c | ||
|   | dc6eaaeb89 | ||
|   | 4953aa02dc | ||
|   | e794647469 | ||
|   | e87bdc9440 | ||
|   | a8f59e0fb5 | ||
|   | 2730a8c5e4 | ||
|   | b3ef448628 | ||
|   | 13fe7d295b | ||
|   | ef1eb190a2 | ||
|   | 370d4aca47 | ||
|   | a575d95b91 | ||
|   | 0477ab5349 | ||
|   | 730f8d169a | ||
|   | be7f50ccbb | ||
|   | 8d681988a9 | ||
|   | 8842f23a8e | 
							
								
								
									
										112
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,6 +13,7 @@ on: | |||||||
|   pull_request: |   pull_request: | ||||||
|     branches: |     branches: | ||||||
|       - main |       - main | ||||||
|  |       - 'release/*' | ||||||
|  |  | ||||||
| defaults: | defaults: | ||||||
|   run: |   run: | ||||||
| @@ -25,45 +26,78 @@ jobs: | |||||||
|       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io |       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|       DOCKER_REGISTRY_USERNAME: ucentral |       DOCKER_REGISTRY_USERNAME: ucentral | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v2 |     - name: Checkout actions repo | ||||||
|  |       uses: actions/checkout@v2 | ||||||
|     - name: Build Docker image |  | ||||||
|       run: docker build -t wlan-cloud-owsec:${{ github.sha }} . |  | ||||||
|  |  | ||||||
|     - name: Tag Docker image |  | ||||||
|       run: | |  | ||||||
|         TAGS="${{ github.sha }}" |  | ||||||
|  |  | ||||||
|         if [[ ${GITHUB_REF} == "refs/heads/"* ]] |  | ||||||
|         then |  | ||||||
|           CURRENT_TAG=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-') |  | ||||||
|           TAGS="$TAGS $CURRENT_TAG" |  | ||||||
|         else |  | ||||||
|           if [[ ${GITHUB_REF} == "refs/tags/"* ]] |  | ||||||
|           then |  | ||||||
|             CURRENT_TAG=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-') |  | ||||||
|             TAGS="$TAGS $CURRENT_TAG" |  | ||||||
|           else # PR build |  | ||||||
|             CURRENT_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') |  | ||||||
|             TAGS="$TAGS $CURRENT_TAG" |  | ||||||
|           fi |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         echo "Result tags: $TAGS" |  | ||||||
|  |  | ||||||
|         for tag in $TAGS; do |  | ||||||
|           docker tag wlan-cloud-owsec:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owsec:$tag |  | ||||||
|         done |  | ||||||
|  |  | ||||||
|     - name: Log into Docker registry |  | ||||||
|       if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main' |  | ||||||
|       uses: docker/login-action@v1 |  | ||||||
|       with: |       with: | ||||||
|         registry: ${{ env.DOCKER_REGISTRY_URL }} |         repository: Telecominfraproject/.github | ||||||
|         username: ${{ env.DOCKER_REGISTRY_USERNAME }} |         path: github | ||||||
|         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} |  | ||||||
|  |  | ||||||
|     - name: Push Docker images |     - name: Build and push Docker image | ||||||
|       if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main' |       uses: ./github/composite-actions/docker-image-build | ||||||
|  |       with: | ||||||
|  |         image_name: owsec | ||||||
|  |         registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|  |         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 | ||||||
|  |     needs: docker | ||||||
|  |     steps: | ||||||
|  |     - name: Get base branch name and set as output | ||||||
|  |       id: get_base_branch | ||||||
|       run: | |       run: | | ||||||
|         docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owsec | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {} |         echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/}) | ||||||
|  |         echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g') | ||||||
|  |  | ||||||
|  |     - name: Checkout actions repo | ||||||
|  |       uses: actions/checkout@v2 | ||||||
|  |       with: | ||||||
|  |         repository: Telecominfraproject/.github | ||||||
|  |         path: github | ||||||
|  |  | ||||||
|  |     - name: Trigger testing of OpenWifi Docker Compose deployment and wait for result | ||||||
|  |       uses: ./github/composite-actions/trigger-workflow-and-wait | ||||||
|  |       env: | ||||||
|  |         BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }} | ||||||
|  |         OWGW_BASE_BRANCH: ${{ steps.get_base_branch.outputs.owgw_branch }} | ||||||
|  |       with: | ||||||
|  |         owner: Telecominfraproject | ||||||
|  |         repo: wlan-testing | ||||||
|  |         workflow: ow_docker-compose.yml | ||||||
|  |         token: ${{ secrets.WLAN_TESTING_PAT }} | ||||||
|  |         ref: master | ||||||
|  |         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: |   pull_request: | ||||||
|     branches: |     branches: | ||||||
|       - main |       - main | ||||||
|  |       - 'release/*' | ||||||
|     types: [ closed ] |     types: [ closed ] | ||||||
|  |  | ||||||
| defaults: | defaults: | ||||||
| @@ -16,4 +17,10 @@ jobs: | |||||||
|     steps: |     steps: | ||||||
|       - run: | |       - run: | | ||||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') |           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 | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | name: Ensure Jira issue is linked | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     types: [opened, edited, reopened, synchronize] | ||||||
|  |     branches: | ||||||
|  |       - 'release/*' | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   check_for_issue_key: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout actions repo | ||||||
|  |         uses: actions/checkout@v2 | ||||||
|  |         with: | ||||||
|  |           repository: Telecominfraproject/.github | ||||||
|  |           path: github | ||||||
|  |  | ||||||
|  |       - name: Run JIRA check | ||||||
|  |         uses: ./github/composite-actions/enforce-jira-issue-key | ||||||
|  |         with: | ||||||
|  |           jira_base_url: ${{ secrets.TIP_JIRA_URL }} | ||||||
|  |           jira_user_email: ${{ secrets.TIP_JIRA_USER_EMAIL }} | ||||||
|  |           jira_api_token: ${{ secrets.TIP_JIRA_API_TOKEN }} | ||||||
							
								
								
									
										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) | cmake_minimum_required(VERSION 3.13) | ||||||
| project(owsec VERSION 2.4.0) | project(owsec VERSION 2.6.0) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 17) | set(CMAKE_CXX_STANDARD 17) | ||||||
|  |  | ||||||
| @@ -20,27 +20,43 @@ endif() | |||||||
|  |  | ||||||
| # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 | # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 | ||||||
| if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) | ||||||
|     file(READ build BUILD_NUM) |     file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM) | ||||||
|     if(BUILD_INCREMENT) |     if(BUILD_INCREMENT) | ||||||
|         MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") |         MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") | ||||||
|         file(WRITE build ${BUILD_NUM}) |         file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) | ||||||
|     endif() |     endif() | ||||||
| else() | else() | ||||||
|     set(BUILD_NUM 1) |     set(BUILD_NUM 1) | ||||||
|     file(WRITE build ${BUILD_NUM}) |     file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | find_package(Git QUIET) | ||||||
|  | if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") | ||||||
|  |     execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags | ||||||
|  |             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||||||
|  |             RESULT_VARIABLE GIT_RESULT | ||||||
|  |             OUTPUT_VARIABLE GIT_HASH) | ||||||
|  |     if(NOT GIT_RESULT EQUAL "0") | ||||||
|  |         message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}") | ||||||
|  |     endif() | ||||||
|  |     string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT) | ||||||
|  |  | ||||||
| set(BUILD_SHARED_LIBS 1) | set(BUILD_SHARED_LIBS 1) | ||||||
|  |  | ||||||
| add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}") |  | ||||||
| add_definitions(-DTIP_SECURITY_SERVICE="1") | add_definitions(-DTIP_SECURITY_SERVICE="1") | ||||||
|  |  | ||||||
| set(Boost_USE_STATIC_LIBS OFF) | add_compile_options(-Wall -Wextra) | ||||||
| set(Boost_USE_MULTITHREADED ON) | if(ASAN) | ||||||
| set(Boost_USE_STATIC_RUNTIME OFF) |     add_compile_options(-fsanitize=address) | ||||||
| find_package(Boost REQUIRED system) |     add_link_options(-fsanitize=address) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| find_package(OpenSSL REQUIRED) | find_package(OpenSSL REQUIRED) | ||||||
| find_package(ZLIB REQUIRED) | find_package(ZLIB REQUIRED) | ||||||
|  | find_package(fmt  REQUIRED) | ||||||
| find_package(AWSSDK     REQUIRED COMPONENTS sns) | find_package(AWSSDK     REQUIRED COMPONENTS sns) | ||||||
| find_package(nlohmann_json  REQUIRED) | find_package(nlohmann_json  REQUIRED) | ||||||
| find_package(CppKafka REQUIRED) | find_package(CppKafka REQUIRED) | ||||||
| @@ -50,35 +66,47 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS | |||||||
|  |  | ||||||
| include_directories(/usr/local/include  /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include) | include_directories(/usr/local/include  /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include) | ||||||
|  |  | ||||||
|  | configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY) | ||||||
|  |  | ||||||
| add_executable( owsec | add_executable( owsec | ||||||
|         build |         build | ||||||
|  |         src/ow_version.h.in | ||||||
|         src/framework/CountryCodes.h |         src/framework/CountryCodes.h | ||||||
|         src/framework/KafkaTopics.h |         src/framework/KafkaTopics.h | ||||||
|         src/framework/MicroService.h |         src/framework/MicroService.h | ||||||
|         src/framework/OpenWifiTypes.h |  | ||||||
|         src/framework/orm.h |         src/framework/orm.h | ||||||
|         src/framework/RESTAPI_errors.h |  | ||||||
|         src/framework/RESTAPI_protocol.h |  | ||||||
|         src/framework/StorageClass.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 | ||||||
|  |         src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h | ||||||
|         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp |         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp | ||||||
|         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h |         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h | ||||||
|         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp |         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp | ||||||
|         src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp |         src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp | ||||||
|         src/RESTAPI/RESTAPI_oauth2Handler.h src/RESTAPI/RESTAPI_oauth2Handler.cpp |         src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp | ||||||
|         src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h |         src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h | ||||||
|         src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h |         src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h | ||||||
|         src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h |         src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h | ||||||
|         src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h |         src/RESTAPI/RESTAPI_validate_token_handler.cpp src/RESTAPI/RESTAPI_validate_token_handler.h | ||||||
|         src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h |         src/RESTAPI/RESTAPI_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h | ||||||
|         src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h |         src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h | ||||||
|         src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.h |         src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h | ||||||
|  |         src/RESTAPI/RESTAPI_subavatar_handler.cpp src/RESTAPI/RESTAPI_subavatar_handler.h | ||||||
|         src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h |         src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h | ||||||
|         src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h |         src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h | ||||||
|         src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h |         src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp | ||||||
|         src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp |         src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp | ||||||
|         src/APIServers.cpp |         src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp | ||||||
|  |         src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp src/RESTAPI/RESTAPI_validate_sub_token_handler.h | ||||||
|  |         src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h | ||||||
|  |         src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h | ||||||
|  |         src/RESTAPI/RESTAPI_subpreferences.cpp src/RESTAPI/RESTAPI_subpreferences.h | ||||||
|  |         src/RESTAPI/RESTAPI_routers.cpp | ||||||
|         src/Daemon.h src/Daemon.cpp |         src/Daemon.h src/Daemon.cpp | ||||||
|  |         src/SpecialUserHelpers.h | ||||||
|         src/AuthService.h src/AuthService.cpp |         src/AuthService.h src/AuthService.cpp | ||||||
|         src/StorageService.cpp src/StorageService.h |         src/StorageService.cpp src/StorageService.h | ||||||
|         src/SMTPMailerService.cpp src/SMTPMailerService.h |         src/SMTPMailerService.cpp src/SMTPMailerService.h | ||||||
| @@ -87,15 +115,25 @@ add_executable( owsec | |||||||
|         src/SMS_provider_aws.cpp src/SMS_provider_aws.h |         src/SMS_provider_aws.cpp src/SMS_provider_aws.h | ||||||
|         src/SMS_provider.cpp src/SMS_provider.h |         src/SMS_provider.cpp src/SMS_provider.h | ||||||
|         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h |         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h | ||||||
|         src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h |  | ||||||
|         src/storage/storage_tokens.h |  | ||||||
|         src/ActionLinkManager.cpp src/ActionLinkManager.h |         src/ActionLinkManager.cpp src/ActionLinkManager.h | ||||||
|         src/ACLProcessor.h) |         src/ACLProcessor.h | ||||||
|  |         src/framework/OpenWifiTypes.h | ||||||
|  |         src/storage/orm_users.cpp src/storage/orm_users.h | ||||||
|  |         src/storage/orm_tokens.cpp src/storage/orm_tokens.h | ||||||
|  |         src/storage/orm_preferences.cpp src/storage/orm_preferences.h | ||||||
|  |         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_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h) | ||||||
|  |  | ||||||
| if(NOT SMALL_BUILD) | if(NOT SMALL_BUILD) | ||||||
|     target_link_libraries(owsec PUBLIC |     target_link_libraries(owsec PUBLIC | ||||||
|             ${Poco_LIBRARIES} ${Boost_LIBRARIES} ${MySQL_LIBRARIES}  ${ZLIB_LIBRARIES} |             ${Poco_LIBRARIES} | ||||||
|             CppKafka::cppkafka ${AWSSDK_LINK_LIBRARIES} |             ${MySQL_LIBRARIES} | ||||||
|  |             ${ZLIB_LIBRARIES} | ||||||
|  |             CppKafka::cppkafka | ||||||
|  |             ${AWSSDK_LINK_LIBRARIES} | ||||||
|  |             fmt::fmt | ||||||
|             ) |             ) | ||||||
|     if(UNIX AND NOT APPLE) |     if(UNIX AND NOT APPLE) | ||||||
|         target_link_libraries(owsec PUBLIC PocoJSON) |         target_link_libraries(owsec PUBLIC PocoJSON) | ||||||
|   | |||||||
							
								
								
									
										132
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,18 +1,63 @@ | |||||||
| FROM alpine AS builder | FROM alpine:3.15 AS build-base | ||||||
|  |  | ||||||
| RUN apk add --update --no-cache \ | RUN apk add --update --no-cache \ | ||||||
|     openssl openssh \ |     make cmake g++ git \ | ||||||
|     ncurses-libs \ |     unixodbc-dev postgresql-dev mariadb-dev \ | ||||||
|     bash util-linux coreutils curl libcurl \ |     librdkafka-dev boost-dev openssl-dev \ | ||||||
|     make cmake gcc g++ libstdc++ libgcc git zlib-dev \ |     zlib-dev nlohmann-json \ | ||||||
|     openssl-dev boost-dev curl-dev unixodbc-dev postgresql-dev mariadb-dev \ |     curl-dev | ||||||
|     apache2-utils yaml-dev apr-util-dev \ |  | ||||||
|     librdkafka-dev |  | ||||||
|  |  | ||||||
|  | FROM build-base AS poco-build | ||||||
|  |  | ||||||
|  | ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json | ||||||
| RUN git clone https://github.com/stephb9959/poco /poco | RUN git clone https://github.com/stephb9959/poco /poco | ||||||
|  |  | ||||||
|  | WORKDIR /poco | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | 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 | ||||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | ||||||
| RUN git clone https://github.com/nlohmann/json /json |  | ||||||
|  | WORKDIR /cppkafka | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN cmake --build . --config Release -j8 | ||||||
|  | RUN cmake --build . --target install | ||||||
|  |  | ||||||
|  | FROM build-base AS json-schema-validator-build | ||||||
|  |  | ||||||
|  | ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json | ||||||
| RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | ||||||
|  |  | ||||||
|  | WORKDIR /json-schema-validator | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN make | ||||||
|  | RUN make install | ||||||
|  |  | ||||||
|  | FROM build-base AS aws-sdk-cpp-build | ||||||
|  |  | ||||||
|  | ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json | ||||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | ||||||
|  |  | ||||||
| WORKDIR /aws-sdk-cpp | WORKDIR /aws-sdk-cpp | ||||||
| @@ -25,45 +70,34 @@ RUN cmake .. -DBUILD_ONLY="sns;s3" \ | |||||||
| RUN cmake --build . --config Release -j8 | RUN cmake --build . --config Release -j8 | ||||||
| RUN cmake --build . --target install | RUN cmake --build . --target install | ||||||
|  |  | ||||||
| WORKDIR /cppkafka | FROM build-base AS owsec-build | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN cmake --build . --config Release -j8 |  | ||||||
| RUN cmake --build . --target install |  | ||||||
|  |  | ||||||
| WORKDIR /poco |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN cmake --build . --config Release -j8 |  | ||||||
| RUN cmake --build . --target install |  | ||||||
|  |  | ||||||
| WORKDIR /json |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN make |  | ||||||
| RUN make install |  | ||||||
|  |  | ||||||
| WORKDIR /json-schema-validator |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN make |  | ||||||
| RUN make install |  | ||||||
|  |  | ||||||
| ADD CMakeLists.txt build /owsec/ | ADD CMakeLists.txt build /owsec/ | ||||||
| ADD cmake /owsec/cmake | ADD cmake /owsec/cmake | ||||||
| ADD src /owsec/src | ADD src /owsec/src | ||||||
|  | ADD .git /owsec/.git | ||||||
|  |  | ||||||
|  | COPY --from=poco-build /usr/local/include /usr/local/include | ||||||
|  | COPY --from=poco-build /usr/local/lib /usr/local/lib | ||||||
|  | COPY --from=cppkafka-build /usr/local/include /usr/local/include | ||||||
|  | COPY --from=cppkafka-build /usr/local/lib /usr/local/lib | ||||||
|  | COPY --from=json-schema-validator-build /usr/local/include /usr/local/include | ||||||
|  | COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib | ||||||
|  | COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include | ||||||
|  | COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib | ||||||
|  |  | ||||||
|  | COPY --from=fmtlib-build /usr/local/include /usr/local/include | ||||||
|  | COPY --from=fmtlib-build /usr/local/lib /usr/local/lib | ||||||
|  |  | ||||||
| WORKDIR /owsec | WORKDIR /owsec | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| WORKDIR /owsec/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 | RUN cmake --build . --config Release -j8 | ||||||
|  |  | ||||||
| FROM alpine | FROM alpine:3.15 | ||||||
|  |  | ||||||
| ENV OWSEC_USER=owsec \ | ENV OWSEC_USER=owsec \ | ||||||
|     OWSEC_ROOT=/owsec-data \ |     OWSEC_ROOT=/owsec-data \ | ||||||
| @@ -75,23 +109,27 @@ RUN addgroup -S "$OWSEC_USER" && \ | |||||||
| RUN mkdir /openwifi | RUN mkdir /openwifi | ||||||
| RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ | RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ | ||||||
|     chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" |     chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" | ||||||
| RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl |  | ||||||
| COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec | RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \ | ||||||
| COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/ |     mariadb-connector-c libpq unixodbc postgresql-client | ||||||
| COPY --from=builder /poco/cmake-build/lib/* /lib/ |  | ||||||
| COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /lib/ | COPY readiness_check /readiness_check | ||||||
| COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /lib/ | COPY test_scripts/curl/cli /cli | ||||||
| COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /lib/ |  | ||||||
|  |  | ||||||
| COPY owsec.properties.tmpl / | COPY owsec.properties.tmpl / | ||||||
| COPY wwwassets /dist/wwwassets | COPY wwwassets /dist/wwwassets | ||||||
| COPY templates /dist/templates | COPY templates /dist/templates | ||||||
| COPY docker-entrypoint.sh / | COPY docker-entrypoint.sh / | ||||||
|  | COPY wait-for-postgres.sh / | ||||||
| RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | ||||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem |     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem | ||||||
|  |  | ||||||
| COPY readiness_check /readiness_check | COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec | ||||||
| COPY test_scripts/curl/cli /cli | COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib | ||||||
|  | COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib | ||||||
|  | COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib | ||||||
|  | COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib | ||||||
|  | COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib | ||||||
|  |  | ||||||
| EXPOSE 16001 17001 16101 | EXPOSE 16001 17001 16101 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								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 | 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. | 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.group.id = security | ||||||
| openwifi.kafka.client.id = security1 | openwifi.kafka.client.id = security1 | ||||||
| openwifi.kafka.enable = true | 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 | - `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. | - `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.backlog = 100 | ||||||
| openwifi.restapi.host.0.security = relaxed | openwifi.restapi.host.0.security = relaxed | ||||||
| openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | 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  | 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. | to the filenames used in the previous section. | ||||||
|  |  | ||||||
| ```asm | ``` | ||||||
| openwifi.internal.restapi.host.0.backlog = 100 | openwifi.internal.restapi.host.0.backlog = 100 | ||||||
| openwifi.internal.restapi.host.0.security = relaxed | openwifi.internal.restapi.host.0.security = relaxed | ||||||
| openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | 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. | Here are other important values you must set. | ||||||
|  |  | ||||||
|  |  | ||||||
| ```asm | ``` | ||||||
| openwifi.system.data = $OWSEC_ROOT/data | openwifi.system.data = $OWSEC_ROOT/data | ||||||
| openwifi.system.uri.private = https://localhost:17001 | openwifi.system.uri.private = https://localhost:17001 | ||||||
| openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001 | openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001 | ||||||
| @@ -218,10 +218,11 @@ This is the FQDN used externally serving the OpenAPI interface. | |||||||
| `owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so, | `owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so, | ||||||
| an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS | an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS | ||||||
|  |  | ||||||
| #### AWS SNS | #### AWS SMS | ||||||
| For SNS you must create an IAM ID that has sns:sendmessage rights.  | For SNS you must create an IAM ID that has sns:sendmessage rights.   | ||||||
|  |  | ||||||
| ```asm | ``` | ||||||
|  | smssender.enabled = true | ||||||
| smssender.provider = aws | smssender.provider = aws | ||||||
| smssender.aws.secretkey = *************************************** | smssender.aws.secretkey = *************************************** | ||||||
| smssender.aws.accesskey = *************************************** | smssender.aws.accesskey = *************************************** | ||||||
| @@ -231,7 +232,8 @@ smssender.aws.region = ************** | |||||||
| #### Twilio | #### Twilio | ||||||
| For Twilio, you must provide the following | For Twilio, you must provide the following | ||||||
|  |  | ||||||
| ```asm | ``` | ||||||
|  | smssender.enabled = true | ||||||
| smssender.provider = twilio | smssender.provider = twilio | ||||||
| smssender.twilio.sid = *********************** | smssender.twilio.sid = *********************** | ||||||
| smssender.twilio.token = ********************** | 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 | 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. | as the proper mail host. | ||||||
|  |  | ||||||
| ```asm | ``` | ||||||
|  | mailer.enabled = true | ||||||
| mailer.hostname = smtp.gmail.com | mailer.hostname = smtp.gmail.com | ||||||
| mailer.username = ************************ | mailer.username = ************************ | ||||||
| mailer.password = ************************ | mailer.password = ************************ | ||||||
| @@ -252,3 +255,13 @@ mailer.loginmethod = login | |||||||
| mailer.port = 587 | mailer.port = 587 | ||||||
| mailer.templates = $OWSEC_ROOT/templates | mailer.templates = $OWSEC_ROOT/templates | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | #### Google 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 | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | totp.issuer = OrgName | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | It is very important that you not use spaces in your OrgName. | ||||||
| @@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then | |||||||
|     update-ca-certificates |     update-ca-certificates | ||||||
| fi | 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_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \ | ||||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ |   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ | ||||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ |   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ | ||||||
| @@ -25,14 +25,27 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; t | |||||||
|   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ |   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ | ||||||
|   SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ |   SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ | ||||||
|   SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ |   SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ | ||||||
|   MAILER_HOSTNAME=${MAILER_HOSTNAME:-"smtp.gmail.com"} \ |   SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \ | ||||||
|   MAILER_USERNAME=${MAILER_USERNAME:-"************************"} \ |   SMSSENDER_PROVIDER=${SMSSENDER_PROVIDER:-""} \ | ||||||
|   MAILER_PASSWORD=${MAILER_PASSWORD:-"************************"} \ |   SMSSENDER_AWS_SECRETKEY=${SMSSENDER_AWS_SECRETKEY:-""} \ | ||||||
|  |   SMSSENDER_AWS_ACCESSKEY=${SMSSENDER_AWS_ACCESSKEY:-""} \ | ||||||
|  |   SMSSENDER_AWS_REGION=${SMSSENDER_AWS_REGION:-""} \ | ||||||
|  |   SMSSENDER_TWILIO_SID=${SMSSENDER_TWILIO_SID:-""} \ | ||||||
|  |   SMSSENDER_TWILIO_TOKEN=${SMSSENDER_TWILIO_TOKEN:-""} \ | ||||||
|  |   SMSSENDER_TWILIO_PHONENUMBER=${SMSSENDER_TWILIO_PHONENUMBER:-""} \ | ||||||
|  |   MAILER_ENABLED=${MAILER_ENABLED:-"false"} \ | ||||||
|  |   MAILER_HOSTNAME=${MAILER_HOSTNAME:-"localhost"} \ | ||||||
|  |   MAILER_USERNAME=${MAILER_USERNAME:-""} \ | ||||||
|  |   MAILER_PASSWORD=${MAILER_PASSWORD:-""} \ | ||||||
|   MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \ |   MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \ | ||||||
|   MAILER_PORT=${MAILER_PORT:-"587"} \ |   MAILER_PORT=${MAILER_PORT:-"587"} \ | ||||||
|   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ |   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ | ||||||
|   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ |   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ | ||||||
|   KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ |   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_ACCESS=${DOCUMENT_POLICY_ACCESS:-"\$OWSEC_ROOT/persist/wwwassets/access_policy.html"} \ | ||||||
|   DOCUMENT_POLICY_PASSWORD=${DOCUMENT_POLICY_PASSWORD:-"\$OWSEC_ROOT/persist/wwwassets/password_policy.html"} \ |   DOCUMENT_POLICY_PASSWORD=${DOCUMENT_POLICY_PASSWORD:-"\$OWSEC_ROOT/persist/wwwassets/password_policy.html"} \ | ||||||
|   STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ |   STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ | ||||||
|   | |||||||
| @@ -5,14 +5,14 @@ name: owsec | |||||||
| version: 0.1.0 | version: 0.1.0 | ||||||
| dependencies: | dependencies: | ||||||
| - name: postgresql | - name: postgresql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 10.9.2 |   version: 10.9.2 | ||||||
|   condition: postgresql.enabled |   condition: postgresql.enabled | ||||||
| - name: mysql | - name: mysql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 8.8.3 |   version: 8.8.3 | ||||||
|   condition: mysql.enabled |   condition: mysql.enabled | ||||||
| - name: mariadb | - name: mariadb | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 9.4.2 |   version: 9.4.2 | ||||||
|   condition: mariadb.enabled |   condition: mariadb.enabled | ||||||
|   | |||||||
| @@ -30,3 +30,13 @@ Create chart name and version as used by the chart label. | |||||||
| {{- define "owsec.chart" -}} | {{- define "owsec.chart" -}} | ||||||
| {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} | ||||||
| {{- end -}} | {{- 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 -}} | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ spec: | |||||||
|   replicas: {{ .Values.replicaCount }} |   replicas: {{ .Values.replicaCount }} | ||||||
|   strategy: |   strategy: | ||||||
|     type: {{ .Values.strategyType }} |     type: {{ .Values.strategyType }} | ||||||
|  |   revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} | ||||||
|   selector: |   selector: | ||||||
|     matchLabels: |     matchLabels: | ||||||
|       app.kubernetes.io/name: {{ include "owsec.name" . }} |       app.kubernetes.io/name: {{ include "owsec.name" . }} | ||||||
| @@ -35,6 +36,16 @@ spec: | |||||||
|         {{- end }} |         {{- end }} | ||||||
|     spec: |     spec: | ||||||
|  |  | ||||||
|  |       initContainers: | ||||||
|  |         - name: wait-kafka | ||||||
|  |           image: "{{ .Values.images.dockerize.repository }}:{{ .Values.images.dockerize.tag }}" | ||||||
|  |           imagePullPolicy: {{ .Values.images.dockerize.pullPolicy }} | ||||||
|  |           args: | ||||||
|  |             - -wait | ||||||
|  |             - tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }} | ||||||
|  |             - -timeout | ||||||
|  |             - 600s | ||||||
|  |  | ||||||
|       containers: |       containers: | ||||||
|  |  | ||||||
|         - name: owsec |         - name: owsec | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| {{- range $ingress, $ingressValue := .Values.ingresses }} | {{- range $ingress, $ingressValue := .Values.ingresses }} | ||||||
| {{- if $ingressValue.enabled }} | {{- if $ingressValue.enabled }} | ||||||
| --- | --- | ||||||
| apiVersion: extensions/v1beta1 | apiVersion: {{ include "owsec.ingress.apiVersion" $root }} | ||||||
| kind: Ingress | kind: Ingress | ||||||
| metadata: | metadata: | ||||||
|   name: {{ include "owsec.fullname" $root }}-{{ $ingress }} |   name: {{ include "owsec.fullname" $root }}-{{ $ingress }} | ||||||
| @@ -36,9 +36,23 @@ spec: | |||||||
|       paths: |       paths: | ||||||
|       {{- range $ingressValue.paths }} |       {{- range $ingressValue.paths }} | ||||||
|         - path: {{ .path }} |         - path: {{ .path }} | ||||||
|  |           {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }} | ||||||
|  |           pathType: {{ .pathType | default "ImplementationSpecific" }} | ||||||
|  |           {{- end }} | ||||||
|           backend: |           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 }} |             serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }} | ||||||
|             servicePort: {{ .servicePort }} |             servicePort: {{ .servicePort }} | ||||||
|  |             {{- end }} | ||||||
|       {{- end }} |       {{- end }} | ||||||
|   {{- end }} |   {{- end }} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| # System | # System | ||||||
| replicaCount: 1 | replicaCount: 1 | ||||||
| strategyType: Recreate | strategyType: Recreate | ||||||
|  | revisionHistoryLimit: 2 | ||||||
|  |  | ||||||
| nameOverride: "" | nameOverride: "" | ||||||
| fullnameOverride: "" | fullnameOverride: "" | ||||||
| @@ -8,16 +9,20 @@ fullnameOverride: "" | |||||||
| images: | images: | ||||||
|   owsec: |   owsec: | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||||
|     tag: main |     tag: v2.6.0-RC3 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
| #      username: username | #      username: username | ||||||
| #      password: password | #      password: password | ||||||
|  |   dockerize: | ||||||
|  |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize | ||||||
|  |     tag: 0.16.0 | ||||||
|  |     pullPolicy: IfNotPresent | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   owsec: |   owsec: | ||||||
|     type: LoadBalancer |     type: ClusterIP | ||||||
|     ports: |     ports: | ||||||
|       restapi: |       restapi: | ||||||
|         servicePort: 16001 |         servicePort: 16001 | ||||||
| @@ -38,7 +43,6 @@ checks: | |||||||
|       exec: |       exec: | ||||||
|         command: |         command: | ||||||
|           - /readiness_check |           - /readiness_check | ||||||
|       failureThreshold: 1 |  | ||||||
|  |  | ||||||
| ingresses: | ingresses: | ||||||
|   restapi: |   restapi: | ||||||
| @@ -50,6 +54,7 @@ ingresses: | |||||||
|     - restapi.chart-example.local |     - restapi.chart-example.local | ||||||
|     paths: |     paths: | ||||||
|     - path: / |     - path: / | ||||||
|  |       pathType: ImplementationSpecific | ||||||
|       serviceName: owsec |       serviceName: owsec | ||||||
|       servicePort: restapi |       servicePort: restapi | ||||||
|  |  | ||||||
| @@ -162,6 +167,10 @@ configProperties: | |||||||
|   openwifi.kafka.brokerlist: localhost:9092 |   openwifi.kafka.brokerlist: localhost:9092 | ||||||
|   openwifi.kafka.auto.commit: false |   openwifi.kafka.auto.commit: false | ||||||
|   openwifi.kafka.queue.buffering.max.ms: 50 |   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 | ||||||
|   storage.type: sqlite # (sqlite|postgresql|mysql|odbc) |   storage.type: sqlite # (sqlite|postgresql|mysql|odbc) | ||||||
|   ## SQLite |   ## SQLite | ||||||
| @@ -191,22 +200,9 @@ configProperties: | |||||||
|   openwifi.system.uri.ui: https://localhost |   openwifi.system.uri.ui: https://localhost | ||||||
|   openwifi.system.commandchannel: /tmp/app_owsec |   openwifi.system.commandchannel: /tmp/app_owsec | ||||||
|   # Logging |   # Logging | ||||||
|   logging.formatters.f1.class: PatternFormatter |   logging.type: console | ||||||
|   logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t" |   logging.path: $OWSEC_ROOT/logs | ||||||
|   logging.formatters.f1.times: UTC |   logging.level: debug | ||||||
|   logging.channels.c1.class: ConsoleChannel |  | ||||||
|   logging.channels.c1.formatter: f1 |  | ||||||
|   logging.channels.c2.class: FileChannel |  | ||||||
|   logging.channels.c2.path: /tmp/log_owsec |  | ||||||
|   logging.channels.c2.formatter.class: PatternFormatter |  | ||||||
|   logging.channels.c2.formatter.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t" |  | ||||||
|   logging.channels.c2.rotation: "20 M" |  | ||||||
|   logging.channels.c2.archive: timestamp |  | ||||||
|   logging.channels.c2.purgeCount: 20 |  | ||||||
|   logging.channels.c3.class: ConsoleChannel |  | ||||||
|   logging.channels.c3.pattern: "%s: [%p] %t" |  | ||||||
|   logging.loggers.root.channel: c1 |  | ||||||
|   logging.loggers.root.level: debug |  | ||||||
|  |  | ||||||
|   # -> Secret part |   # -> Secret part | ||||||
|   # REST API |   # REST API | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ openapi: 3.0.1 | |||||||
| info: | info: | ||||||
|   title: uCentral Security API |   title: uCentral Security API | ||||||
|   description: A process to manage security logins. |   description: A process to manage security logins. | ||||||
|   version: 2.0.0 |   version: 2.5.0 | ||||||
|   license: |   license: | ||||||
|     name: BSD3 |     name: BSD3 | ||||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE |     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||||
| @@ -61,8 +61,12 @@ components: | |||||||
|                   - 6     # INTERNAL_ERROR, |                   - 6     # INTERNAL_ERROR, | ||||||
|                   - 7     # ACCESS_DENIED, |                   - 7     # ACCESS_DENIED, | ||||||
|                   - 8     # INVALID_TOKEN |                   - 8     # INVALID_TOKEN | ||||||
|                   - 9     # expired token |                   - 9     # EXPIRED_TOKEN | ||||||
|                   - 10    # rate limit exceeded |                   - 10    # RATE_LIMIT_EXCEEDED | ||||||
|  |                   - 11    # BAD_MFA_TRANSACTION | ||||||
|  |                   - 12    # MFA_FAILURE | ||||||
|  |                   - 13    # SECURITY_SERVICE_UNREACHABLE | ||||||
|  |                   - 14    # CANNOT REFRESH TOKEN | ||||||
|               ErrorDetails: |               ErrorDetails: | ||||||
|                 type: string |                 type: string | ||||||
|               ErrorDescription: |               ErrorDescription: | ||||||
| @@ -81,8 +85,20 @@ components: | |||||||
|               Code: |               Code: | ||||||
|                 type: integer |                 type: integer | ||||||
| 
 | 
 | ||||||
|   schemas: |     BadRequest: | ||||||
|  |       description: The requested operation failed. | ||||||
|  |       content: | ||||||
|  |         application/json: | ||||||
|  |           schema: | ||||||
|  |             properties: | ||||||
|  |               ErrorCode: | ||||||
|  |                 type: integer | ||||||
|  |               ErrorDetails: | ||||||
|  |                 type: string | ||||||
|  |               ErrorDescription: | ||||||
|  |                 type: integer | ||||||
| 
 | 
 | ||||||
|  |   schemas: | ||||||
|     WebTokenRequest: |     WebTokenRequest: | ||||||
|       description: User Id and password. |       description: User Id and password. | ||||||
|       type: object |       type: object | ||||||
| @@ -105,6 +121,15 @@ components: | |||||||
|         userId: support@example.com |         userId: support@example.com | ||||||
|         password: support |         password: support | ||||||
| 
 | 
 | ||||||
|  |     WebTokenRefreshRequest: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         userId: | ||||||
|  |           type: string | ||||||
|  |           default: support@example.com | ||||||
|  |         refresh_token: | ||||||
|  |           type: string | ||||||
|  | 
 | ||||||
|     WebTokenResult: |     WebTokenResult: | ||||||
|       description: Login and Refresh Tokens to be used in subsequent API calls. |       description: Login and Refresh Tokens to be used in subsequent API calls. | ||||||
|       type: object |       type: object | ||||||
| @@ -228,7 +253,7 @@ components: | |||||||
|           enum: |           enum: | ||||||
|             - sms |             - sms | ||||||
|             - email |             - email | ||||||
|             - voice |             - authenticator | ||||||
| 
 | 
 | ||||||
|     UserLoginLoginExtensions: |     UserLoginLoginExtensions: | ||||||
|       type: object |       type: object | ||||||
| @@ -237,6 +262,8 @@ components: | |||||||
|           type: array |           type: array | ||||||
|           items: |           items: | ||||||
|             $ref: '#/components/schemas/MobilePhoneNumber' |             $ref: '#/components/schemas/MobilePhoneNumber' | ||||||
|  |         authenticatorSecret: | ||||||
|  |           type: string | ||||||
|         mfa: |         mfa: | ||||||
|           $ref: '#/components/schemas/MfaAuthInfo' |           $ref: '#/components/schemas/MfaAuthInfo' | ||||||
| 
 | 
 | ||||||
| @@ -333,8 +360,14 @@ components: | |||||||
|         securityPolicyChange: |         securityPolicyChange: | ||||||
|           type: integer |           type: integer | ||||||
|           format: int64 |           format: int64 | ||||||
|  |         modified: | ||||||
|  |           type: integer | ||||||
|  |           format: int64 | ||||||
|         userTypeProprietaryInfo: |         userTypeProprietaryInfo: | ||||||
|           $ref: '#/components/schemas/UserLoginLoginExtensions' |           $ref: '#/components/schemas/UserLoginLoginExtensions' | ||||||
|  |         signupUUID: | ||||||
|  |           type: string | ||||||
|  |           format: uuid | ||||||
| 
 | 
 | ||||||
|     UserList: |     UserList: | ||||||
|       type: object |       type: object | ||||||
| @@ -393,6 +426,24 @@ components: | |||||||
|         answer: |         answer: | ||||||
|           type: string |           type: string | ||||||
| 
 | 
 | ||||||
|  |     SubMfaConfig: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         id: | ||||||
|  |           type: string | ||||||
|  |           format: uuid | ||||||
|  |         type: | ||||||
|  |           type: string | ||||||
|  |           enum: | ||||||
|  |             - disabled | ||||||
|  |             - sms | ||||||
|  |             - email | ||||||
|  |         email: | ||||||
|  |           type: string | ||||||
|  |           format: email | ||||||
|  |         sms: | ||||||
|  |           type: string | ||||||
|  | 
 | ||||||
|     ######################################################################################### |     ######################################################################################### | ||||||
|     ## |     ## | ||||||
|     ## These are endpoints that all services in the uCentral stack must provide |     ## These are endpoints that all services in the uCentral stack must provide | ||||||
| @@ -637,6 +688,22 @@ components: | |||||||
|           items: |           items: | ||||||
|             $ref: '#/components/schemas/TagValuePair' |             $ref: '#/components/schemas/TagValuePair' | ||||||
| 
 | 
 | ||||||
|  |     Preferences: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         modified: | ||||||
|  |           type: integer | ||||||
|  |           format: int64 | ||||||
|  |         data: | ||||||
|  |           type: array | ||||||
|  |           items: | ||||||
|  |             type: object | ||||||
|  |             properties: | ||||||
|  |               tag: | ||||||
|  |                 type: string | ||||||
|  |               value: | ||||||
|  |                 type: string | ||||||
|  | 
 | ||||||
|     ######################################################################################### |     ######################################################################################### | ||||||
|     ## |     ## | ||||||
|     ## End of uCentral system wide values |     ## End of uCentral system wide values | ||||||
| @@ -679,6 +746,12 @@ paths: | |||||||
|           schema: |           schema: | ||||||
|             type: boolean |             type: boolean | ||||||
|           required: false |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: grant_type | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |             example: refresh_token | ||||||
|  |           required: false | ||||||
|       requestBody: |       requestBody: | ||||||
|         description: User id and password |         description: User id and password | ||||||
|         required: true |         required: true | ||||||
| @@ -688,6 +761,72 @@ paths: | |||||||
|               oneOf: |               oneOf: | ||||||
|                 - $ref: '#/components/schemas/WebTokenRequest' |                 - $ref: '#/components/schemas/WebTokenRequest' | ||||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' |                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||||
|  |                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: successful operation | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 oneOf: | ||||||
|  |                   - $ref: '#/components/schemas/WebTokenResult' | ||||||
|  |                   - $ref: '#/components/schemas/MFAChallengeRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |   /suboauth2: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - Authentication | ||||||
|  |       summary: Get access token - to be used as Bearer token header for all other API requests. | ||||||
|  |       operationId: getSubAccessToken | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: newPassword | ||||||
|  |           description: used when a user is trying to change her password. This will be the new password. | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: forgotPassword | ||||||
|  |           description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: requirements | ||||||
|  |           description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: resendMFACode | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: completeMFAChallenge | ||||||
|  |           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 | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               oneOf: | ||||||
|  |                 - $ref: '#/components/schemas/WebTokenRequest' | ||||||
|  |                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||||
|  |                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||||
|       responses: |       responses: | ||||||
|         200: |         200: | ||||||
|           description: successful operation |           description: successful operation | ||||||
| @@ -727,6 +866,31 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|  |   /suboauth2/{token}: | ||||||
|  |     delete: | ||||||
|  |       tags: | ||||||
|  |         - Authentication | ||||||
|  |       summary: Revoke a token. | ||||||
|  |       operationId: removeSubAccessToken | ||||||
|  |       parameters: | ||||||
|  |         - in: path | ||||||
|  |           name: token | ||||||
|  |           schema: | ||||||
|  |             type: | ||||||
|  |               string | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         204: | ||||||
|  |           description: successful operation | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 $ref: '#/components/responses/Success' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|   /systemEndpoints: |   /systemEndpoints: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
| @@ -783,6 +947,72 @@ paths: | |||||||
|             type: string |             type: string | ||||||
|             example: id1,id2,id3,id4,id5 |             example: id1,id2,id3,id4,id5 | ||||||
|           required: false |           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' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |   /subusers: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Subscribers | ||||||
|  |       summary: Retrieve a list of existing users as well as some information about them. | ||||||
|  |       operationId: getSubUsers | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: offset | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: limit | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: Selecting this option means the newest record will be returned. Use limit to select how many. | ||||||
|  |           name: filter | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: Return only the ids. | ||||||
|  |           name: idOnly | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: Return only the ids. | ||||||
|  |           name: select | ||||||
|  |           schema: | ||||||
|  |             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: |       responses: | ||||||
|         200: |         200: | ||||||
|           $ref: '#/components/schemas/UserList' |           $ref: '#/components/schemas/UserList' | ||||||
| @@ -881,6 +1111,134 @@ paths: | |||||||
|           schema: |           schema: | ||||||
|             type: boolean |             type: boolean | ||||||
|           required: false |           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: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/UserInfo' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/UserInfo' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |   /subuser/{id}: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Subscribers | ||||||
|  |       operationId: getSubUser | ||||||
|  |       summary: Retrieve the information for a single user. | ||||||
|  |       parameters: | ||||||
|  |         - in: path | ||||||
|  |           name: id | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |             format: uuid | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/UserInfo' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |     delete: | ||||||
|  |       tags: | ||||||
|  |         - Subscribers | ||||||
|  |       operationId: deleteSubUser | ||||||
|  |       summary: Delete a single user. | ||||||
|  |       parameters: | ||||||
|  |         - in: path | ||||||
|  |           name: id | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         204: | ||||||
|  |           $ref: '#/components/responses/Success' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - Subscribers | ||||||
|  |       operationId: createSubUser | ||||||
|  |       summary: Create a single user. | ||||||
|  |       parameters: | ||||||
|  |         - in: path | ||||||
|  |           name: id | ||||||
|  |           #must be set to 0 for user creation | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: true | ||||||
|  |         - in: query | ||||||
|  |           name: email_verification | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |       requestBody: | ||||||
|  |         description: User details (some fields are ignored during creation) | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/UserInfo' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/UserInfo' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|  |     put: | ||||||
|  |       tags: | ||||||
|  |         - Subscribers | ||||||
|  |       operationId: updateSubUser | ||||||
|  |       summary: Modify a single user. | ||||||
|  |       parameters: | ||||||
|  |         - in: path | ||||||
|  |           name: id | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: true | ||||||
|  |         - in: query | ||||||
|  |           name: email_verification | ||||||
|  |           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: |       requestBody: | ||||||
|         description: User details (some fields are ignored during update) |         description: User details (some fields are ignored during update) | ||||||
|         content: |         content: | ||||||
| @@ -1065,6 +1423,219 @@ paths: | |||||||
|                     items: |                     items: | ||||||
|                       type: string |                       type: string | ||||||
| 
 | 
 | ||||||
|  |   /userPreferences: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Preferences | ||||||
|  |       operationId: getUserPreferences | ||||||
|  |       summary: Get the list of recorded preferences for a user | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/Preferences' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - Preferences | ||||||
|  |       operationId: setUserPreferences | ||||||
|  |       summary: Set the list of recorded preferences for a user | ||||||
|  |       requestBody: | ||||||
|  |         description: Setting the list of preferences | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/Preferences' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/Preferences' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  | 
 | ||||||
|  |   /submfa: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - MFA | ||||||
|  |       summary: Retrieve the cyrrent setting for MFA | ||||||
|  |       operationId: getMFS | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/SubMfaConfig' | ||||||
|  | 
 | ||||||
|  |     put: | ||||||
|  |       tags: | ||||||
|  |         - MFA | ||||||
|  |       summary: Retrieve the cyrrent setting for MFA | ||||||
|  |       operationId: modifyMFS | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: startValidation | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: completeValidation | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           name: challengeCode | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: false | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/SubMfaConfig' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/SubMfaConfig' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  | 
 | ||||||
|  |   /totp: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Security | ||||||
|  |       summary: Retrieve the Authenticator QR Code | ||||||
|  |       operationId: getTotpQrCode | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: reset | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |             default: false | ||||||
|  |           required: false | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: QRCode | ||||||
|  |           content: | ||||||
|  |             image/svg+xml: | ||||||
|  |               schema: | ||||||
|  |                 type: string | ||||||
|  |                 format: binary | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  | 
 | ||||||
|  |     put: | ||||||
|  |       tags: | ||||||
|  |         - Security | ||||||
|  |       summary: Send the first security code to validate your setup | ||||||
|  |       operationId: sendToptTestCode | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: value | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |           required: true | ||||||
|  |         - in: query | ||||||
|  |           name: index | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |             format: int64 | ||||||
|  |             example: 1,2,3 | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: Succesful posting of response. | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: object | ||||||
|  |                 properties: | ||||||
|  |                   nextIndex: | ||||||
|  |                     type: integer | ||||||
|  |                   moreCodes: | ||||||
|  |                     type: boolean | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         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 |   ## These are endpoints that all services in the uCentral stack must provide | ||||||
| @@ -1140,6 +1711,27 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|  |   /validateSubToken: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Security | ||||||
|  |         - Subscribers | ||||||
|  |       summary: Allows any microservice to validate a token and get security policy for a specific user. | ||||||
|  |       operationId: validateSubToken | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: token | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/TokenValidationResult' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  | 
 | ||||||
|   /system: |   /system: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
| @@ -82,10 +82,16 @@ openwifi.kafka.enable = true | |||||||
| openwifi.kafka.brokerlist = a1.arilia.com:9092 | openwifi.kafka.brokerlist = a1.arilia.com:9092 | ||||||
| openwifi.kafka.auto.commit = false | openwifi.kafka.auto.commit = false | ||||||
| openwifi.kafka.queue.buffering.max.ms = 50 | 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.access = /wwwassets/access_policy.html | ||||||
| openwifi.document.policy.password = /wwwassets/password_policy.html | openwifi.document.policy.password = /wwwassets/password_policy.html | ||||||
| openwifi.avatar.maxsize = 2000000 | openwifi.avatar.maxsize = 2000000 | ||||||
|  |  | ||||||
|  | totp.issuer = OpenWiFi | ||||||
| # | # | ||||||
| # This section select which form of persistence you need | # This section select which form of persistence you need | ||||||
| # Only one selected at a time. If you select multiple, this service will die if a horrible | # Only one selected at a time. If you select multiple, this service will die if a horrible | ||||||
| @@ -118,44 +124,12 @@ storage.type.mysql.database = ucentral | |||||||
| storage.type.mysql.port = 3306 | storage.type.mysql.port = 3306 | ||||||
| storage.type.mysql.connectiontimeout = 60 | storage.type.mysql.connectiontimeout = 60 | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################################################################## | ######################################################################## | ||||||
| ######################################################################## | ######################################################################## | ||||||
| # | # | ||||||
| # Logging: please leave as is for now. | # Logging: please leave as is for now. | ||||||
| # | # | ||||||
| ######################################################################## | ######################################################################## | ||||||
| logging.formatters.f1.class = PatternFormatter | logging.type = file | ||||||
| logging.formatters.f1.pattern = %s: [%p] %t | logging.path = $OWSEC_ROOT/logs | ||||||
| logging.formatters.f1.times = UTC | logging.level = debug | ||||||
| logging.channels.c1.class = ConsoleChannel |  | ||||||
| logging.channels.c1.formatter = f1 |  | ||||||
|  |  | ||||||
| # This is where the logs will be written. This path MUST exist |  | ||||||
| logging.channels.c2.class = FileChannel |  | ||||||
| logging.channels.c2.path = $OWSEC_ROOT/logs/log |  | ||||||
| logging.channels.c2.formatter.class = PatternFormatter |  | ||||||
| logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t |  | ||||||
| logging.channels.c2.rotation = 20 M |  | ||||||
| logging.channels.c2.archive = timestamp |  | ||||||
| logging.channels.c2.purgeCount = 20 |  | ||||||
| logging.channels.c3.class = ConsoleChannel |  | ||||||
| logging.channels.c3.pattern = %s: [%p] %t |  | ||||||
|  |  | ||||||
| # External Channel |  | ||||||
| logging.loggers.root.channel = c2 |  | ||||||
| logging.loggers.root.level = debug |  | ||||||
|  |  | ||||||
| # Inline Channel with PatternFormatter |  | ||||||
| # logging.loggers.l1.name = logger1 |  | ||||||
| # logging.loggers.l1.channel.class = ConsoleChannel |  | ||||||
| # logging.loggers.l1.channel.pattern = %s: [%p] %t |  | ||||||
| # logging.loggers.l1.level = information |  | ||||||
| # SplitterChannel |  | ||||||
| # logging.channels.splitter.class = SplitterChannel |  | ||||||
| # logging.channels.splitter.channels = l1,l2 |  | ||||||
| # logging.loggers.l2.name = logger2 |  | ||||||
| # logging.loggers.l2.channel = splitter |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -40,9 +40,21 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec | |||||||
| openwifi.service.key = ${SERVICE_KEY} | openwifi.service.key = ${SERVICE_KEY} | ||||||
| openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} | openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} | ||||||
|  |  | ||||||
|  | smssender.enabled = ${SMSSENDER_ENABLED} | ||||||
|  | smssender.provider = ${SMSSENDER_PROVIDER} | ||||||
|  |  | ||||||
|  | smssender.aws.secretkey = ${SMSSENDER_AWS_SECRETKEY} | ||||||
|  | smssender.aws.accesskey = ${SMSSENDER_AWS_ACCESSKEY} | ||||||
|  | smssender.aws.region = ${SMSSENDER_AWS_REGION} | ||||||
|  |  | ||||||
|  | smssender.twilio.sid = ${SMSSENDER_TWILIO_SID} | ||||||
|  | smssender.twilio.token = ${SMSSENDER_TWILIO_TOKEN} | ||||||
|  | smssender.twilio.phonenumber = ${SMSSENDER_TWILIO_PHONENUMBER} | ||||||
|  |  | ||||||
| # | # | ||||||
| # Security Microservice Specific Section | # Security Microservice Specific Section | ||||||
| # | # | ||||||
|  | mailer.enabled = ${MAILER_ENABLED} | ||||||
| mailer.hostname = ${MAILER_HOSTNAME} | mailer.hostname = ${MAILER_HOSTNAME} | ||||||
| mailer.username = ${MAILER_USERNAME} | mailer.username = ${MAILER_USERNAME} | ||||||
| mailer.password = ${MAILER_PASSWORD} | mailer.password = ${MAILER_PASSWORD} | ||||||
| @@ -70,6 +82,10 @@ openwifi.kafka.enable = ${KAFKA_ENABLE} | |||||||
| openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST} | openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST} | ||||||
| openwifi.kafka.auto.commit = false | openwifi.kafka.auto.commit = false | ||||||
| openwifi.kafka.queue.buffering.max.ms = 50 | 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.access = ${DOCUMENT_POLICY_ACCESS} | ||||||
| openwifi.document.policy.password = ${DOCUMENT_POLICY_PASSWORD} | openwifi.document.policy.password = ${DOCUMENT_POLICY_PASSWORD} | ||||||
| @@ -110,37 +126,6 @@ storage.type.mysql.connectiontimeout = 60 | |||||||
| # Logging: please leave as is for now. | # Logging: please leave as is for now. | ||||||
| # | # | ||||||
| ######################################################################## | ######################################################################## | ||||||
| logging.formatters.f1.class = PatternFormatter | logging.type = console | ||||||
| logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t | logging.path = $OWSEC_ROOT/logs | ||||||
| logging.formatters.f1.times = UTC | logging.level = debug | ||||||
| logging.channels.c1.class = ConsoleChannel |  | ||||||
| logging.channels.c1.formatter = f1 |  | ||||||
|  |  | ||||||
| # This is where the logs will be written. This path MUST exist |  | ||||||
| logging.channels.c2.class = FileChannel |  | ||||||
| logging.channels.c2.path = $OWSEC_ROOT/logs/log |  | ||||||
| logging.channels.c2.formatter.class = PatternFormatter |  | ||||||
| logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t |  | ||||||
| logging.channels.c2.rotation = 20 M |  | ||||||
| logging.channels.c2.archive = timestamp |  | ||||||
| logging.channels.c2.purgeCount = 20 |  | ||||||
| logging.channels.c3.class = ConsoleChannel |  | ||||||
| logging.channels.c3.pattern = %s: [%p] %t |  | ||||||
|  |  | ||||||
| # External Channel |  | ||||||
| logging.loggers.root.channel = c1 |  | ||||||
| logging.loggers.root.level = debug |  | ||||||
|  |  | ||||||
| # Inline Channel with PatternFormatter |  | ||||||
| # logging.loggers.l1.name = logger1 |  | ||||||
| # logging.loggers.l1.channel.class = ConsoleChannel |  | ||||||
| # logging.loggers.l1.channel.pattern = %s: [%p] %t |  | ||||||
| # logging.loggers.l1.level = information |  | ||||||
| # SplitterChannel |  | ||||||
| # logging.channels.splitter.class = SplitterChannel |  | ||||||
| # logging.channels.splitter.channels = l1,l2 |  | ||||||
| # logging.loggers.l2.name = logger2 |  | ||||||
| # logging.loggers.l2.channel = splitter |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,22 +13,23 @@ then | |||||||
|   exit 1 |   exit 1 | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ "${OWSEC_USERNAME}" == "" ]] |  | ||||||
| then |  | ||||||
|   echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like" |  | ||||||
|   echo "OWSEC_USERNAME=tip@ucentral.com" |  | ||||||
|   exit 1 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if [[ "${OWSEC_PASSWORD}" == "" ]] |  | ||||||
| then |  | ||||||
|   echo "You must set the variable OWSEC_PASSWORD in order to use this script. Something like" |  | ||||||
|   echo "OWSEC_PASSWORD=openwifi" |  | ||||||
|   exit 1 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if [[ "${READINESS_METHOD}" == "systeminfo" ]] | if [[ "${READINESS_METHOD}" == "systeminfo" ]] | ||||||
| then | then | ||||||
|  |   if [[ "${OWSEC_USERNAME}" == "" ]] | ||||||
|  |   then | ||||||
|  |     echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like" | ||||||
|  |     echo "OWSEC_USERNAME=tip@ucentral.com" | ||||||
|  |     exit 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   if [[ "${OWSEC_PASSWORD}" == "" ]] | ||||||
|  |   then | ||||||
|  |     echo "You must set the variable OWSEC_PASSWORD in order to use this script. Something like" | ||||||
|  |     echo "OWSEC_PASSWORD=openwifi" | ||||||
|  |     exit 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|   export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWSEC_CONFIG/owsec.properties | awk -F '=' '{print $2}' | xargs | envsubst) |   export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWSEC_CONFIG/owsec.properties | awk -F '=' '{print $2}' | xargs | envsubst) | ||||||
|   # Get OAuth token from OWSEC and cache it or use cached one |   # Get OAuth token from OWSEC and cache it or use cached one | ||||||
|   payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }" |   payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }" | ||||||
|   | |||||||
| @@ -17,22 +17,67 @@ namespace OpenWifi { | |||||||
|             DELETE, |             DELETE, | ||||||
|             CREATE |             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 | ||||||
|  |     4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT | ||||||
|  |     5) Creation rules: | ||||||
|  |         ROOT -> create anything | ||||||
|  |         PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning | ||||||
|  |         ADMIN -> admin-subs-csr-installer-noc-accounting | ||||||
|  |         ACCOUNTING -> subs-installer-csr | ||||||
|  |  | ||||||
|  |  */ | ||||||
|         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { |         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { | ||||||
|             if(User.Id == Target.Id && Op==DELETE) |  | ||||||
|  |             // 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; |                 return false; | ||||||
|  |  | ||||||
|  |             //  rule 2 | ||||||
|             if(User.userRole==SecurityObjects::ROOT) |             if(User.userRole==SecurityObjects::ROOT) | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             if(User.Id == Target.Id) |             //  rule 3 | ||||||
|  |             if(User.id == Target.id) | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             if(User.userRole!=SecurityObjects::ADMIN && User.userRole!=SecurityObjects::ROOT && Op!=READ) |             //  rule 4 | ||||||
|                 return false; |  | ||||||
|  |  | ||||||
|             if(Target.userRole==SecurityObjects::ROOT && Op!=READ) |             if(Target.userRole==SecurityObjects::ROOT && Op!=READ) | ||||||
|                 return false; |                 return false; | ||||||
|  |  | ||||||
|  |             if(Op==CREATE) { | ||||||
|  |                 if(User.userRole==SecurityObjects::ROOT) | ||||||
|  |                     return true; | ||||||
|  |                 if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN || | ||||||
|  |                     Target.userRole==SecurityObjects::SUBSCRIBER || | ||||||
|  |                     Target.userRole==SecurityObjects::CSR || | ||||||
|  |                     Target.userRole==SecurityObjects::INSTALLER || | ||||||
|  |                     Target.userRole==SecurityObjects::NOC || | ||||||
|  |                     Target.userRole==SecurityObjects::ACCOUNTING)) | ||||||
|  |                     return true; | ||||||
|  |                 if(User.userRole==SecurityObjects::ADMIN && | ||||||
|  |                     (Target.userRole==SecurityObjects::ADMIN || | ||||||
|  |                     Target.userRole==SecurityObjects::SUBSCRIBER || | ||||||
|  |                     Target.userRole==SecurityObjects::CSR || | ||||||
|  |                     Target.userRole==SecurityObjects::INSTALLER || | ||||||
|  |                     Target.userRole==SecurityObjects::NOC || | ||||||
|  |                     Target.userRole==SecurityObjects::ACCOUNTING)) | ||||||
|  |                     return true; | ||||||
|  |                 if(User.userRole==SecurityObjects::ACCOUNTING && | ||||||
|  |                     (Target.userRole==SecurityObjects::SUBSCRIBER || | ||||||
|  |                     Target.userRole==SecurityObjects::INSTALLER || | ||||||
|  |                     Target.userRole==SecurityObjects::CSR)) | ||||||
|  |                     return true; | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|     private: |     private: | ||||||
|   | |||||||
| @@ -1,47 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-23. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| #include "RESTAPI/RESTAPI_oauth2Handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_user_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_users_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_action_links.h" |  | ||||||
| #include "RESTAPI/RESTAPI_systemEndpoints_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_AssetServer.h" |  | ||||||
| #include "RESTAPI/RESTAPI_avatarHandler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_email_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_sms_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_validateToken_handler.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, |  | ||||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S) { |  | ||||||
|         return RESTAPI_Router< |  | ||||||
|             RESTAPI_oauth2Handler, |  | ||||||
|             RESTAPI_users_handler, |  | ||||||
|             RESTAPI_user_handler, |  | ||||||
|             RESTAPI_system_command, |  | ||||||
|             RESTAPI_AssetServer, |  | ||||||
|             RESTAPI_systemEndpoints_handler, |  | ||||||
|             RESTAPI_action_links, |  | ||||||
|             RESTAPI_avatarHandler, |  | ||||||
|             RESTAPI_email_handler, |  | ||||||
|             RESTAPI_sms_handler |  | ||||||
|         >(Path, Bindings, L, S); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_internal_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, |  | ||||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S) { |  | ||||||
|         return RESTAPI_Router_I< |  | ||||||
|             RESTAPI_users_handler, |  | ||||||
|             RESTAPI_user_handler, |  | ||||||
|             RESTAPI_system_command, |  | ||||||
|             RESTAPI_action_links, |  | ||||||
|             RESTAPI_validateToken_handler, |  | ||||||
|             RESTAPI_sms_handler |  | ||||||
|         >(Path, Bindings, L, S); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -24,6 +24,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void ActionLinkManager::run() { |     void ActionLinkManager::run() { | ||||||
|         Running_ = true ; |         Running_ = true ; | ||||||
|  |         Utils::SetThreadName("action-mgr"); | ||||||
|  |  | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(2000); |             Poco::Thread::trySleep(2000); | ||||||
| @@ -32,7 +33,7 @@ namespace OpenWifi { | |||||||
|             std::vector<SecurityObjects::ActionLink>    Links; |             std::vector<SecurityObjects::ActionLink>    Links; | ||||||
|             { |             { | ||||||
|                 std::lock_guard G(Mutex_); |                 std::lock_guard G(Mutex_); | ||||||
|                 StorageService()->GetActions(Links); |                 StorageService()->ActionLinksDB().GetActions(Links); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(Links.empty()) |             if(Links.empty()) | ||||||
| @@ -43,23 +44,61 @@ namespace OpenWifi { | |||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|                 SecurityObjects::UserInfo UInfo; |                 SecurityObjects::UserInfo UInfo; | ||||||
|                 if(!StorageService()->GetUserById(i.userId,UInfo)) { |                 if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD || | ||||||
|                     StorageService()->CancelAction(i.id); |                     i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) { | ||||||
|  |                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||||
|  |                     continue; | ||||||
|  |                 } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD || | ||||||
|  |                             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; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if(i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD) { |                 switch(i.action) { | ||||||
|                     if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { |                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { | ||||||
|                         Logger_.information(Poco::format("Send password reset link to %s",UInfo.email)); |                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||||
|  |                                 Logger().information(fmt::format("Send password reset link to {}",UInfo.email)); | ||||||
|  |                             } | ||||||
|  |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|  |                     case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: { | ||||||
|  |                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||||
|  |                                 Logger().information(fmt::format("Send email verification link to {}",UInfo.email)); | ||||||
|  |                             } | ||||||
|  |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|  |                     case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: { | ||||||
|  |                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||||
|  |                                 Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email)); | ||||||
|  |                             } | ||||||
|  |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|  |                     case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: { | ||||||
|  |                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||||
|  |                                 Logger().information(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); | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|  |                     default: { | ||||||
|  |                         StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|                     } |                     } | ||||||
|                     StorageService()->SentAction(i.id); |  | ||||||
|                 } else if (i.action==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)); |  | ||||||
|                     } |  | ||||||
|                     StorageService()->SentAction(i.id); |  | ||||||
|                 } else { |  | ||||||
|                     StorageService()->SentAction(i.id); |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -12,19 +12,22 @@ namespace OpenWifi { | |||||||
|     class ActionLinkManager : public SubSystemServer, Poco::Runnable { |     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|         enum Actions { | /*        enum Actions { | ||||||
|             FORGOT_PASSWORD, |             FORGOT_PASSWORD, | ||||||
|             VERIFY_EMAIL |             VERIFY_EMAIL, | ||||||
|  |             SUB_FORGOT_PASSWORD, | ||||||
|  |             SUB_VERIFY_EMAIL, | ||||||
|  |             SUB_SIGNUP | ||||||
|         }; |         }; | ||||||
|  | */ | ||||||
|         static ActionLinkManager * instance() { |         static ActionLinkManager * instance() { | ||||||
|             static auto * instance_ = new ActionLinkManager; |             static auto instance_ = new ActionLinkManager; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Start() final; |         int Start() final; | ||||||
|         void Stop() final; |         void Stop() final; | ||||||
|         void run(); |         void run() final; | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         Poco::Thread        Thr_; |         Poco::Thread        Thr_; | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ namespace OpenWifi { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	int AuthService::AccessTypeToInt(ACCESS_TYPE T) { | 	int AuthService::AccessTypeToInt(ACCESS_TYPE T) { | ||||||
| 		switch (T) { | 		switch (T) { | ||||||
| 		case USERNAME: return 1; | 		case USERNAME: return 1; | ||||||
| @@ -42,21 +43,106 @@ namespace OpenWifi { | |||||||
| 		return 1;	// some compilers complain... | 		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() { |     int AuthService::Start() { | ||||||
| 		Signer_.setRSAKey(MicroService::instance().Key()); | 		Logger().notice("Starting..."); | ||||||
| 		Signer_.addAllAlgorithms(); |  | ||||||
| 		Logger_.notice("Starting..."); |  | ||||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); |  | ||||||
|         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); |         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); |         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",DefaultPassword_8_u_l_n_1); | ||||||
|  |  | ||||||
|  |         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"); | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AuthService::Stop() { |     void AuthService::Stop() { | ||||||
| 		Logger_.notice("Stopping..."); | 		Logger().notice("Stopping..."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) |     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_); |         std::lock_guard	Guard(Mutex_); | ||||||
|         Expired = false; |         Expired = false; | ||||||
| @@ -67,89 +153,139 @@ namespace OpenWifi { | |||||||
| 		        CallToken = Auth.getBearerToken(); | 		        CallToken = Auth.getBearerToken(); | ||||||
| 		    } | 		    } | ||||||
|  |  | ||||||
| 		    if(!CallToken.empty()) { |             if(CallToken.empty()) { | ||||||
| 		        auto Client = UserCache_.get(CallToken); |                 return false; | ||||||
| 		        if( Client.isNull() ) { |             } | ||||||
| 		            SecurityObjects::UserInfoAndPolicy UInfo2; |  | ||||||
| 		            uint64_t RevocationDate=0; |             SecurityObjects::WebToken   WT; | ||||||
| 		            if(StorageService()->GetToken(CallToken,UInfo2,RevocationDate)) { |             uint64_t                    RevocationDate=0; | ||||||
| 		                if(RevocationDate!=0) |             std::string                 UserId; | ||||||
| 		                    return false; |             if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||||
| 		                Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr); |                 if(RevocationDate!=0) | ||||||
| 		                if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) { |                     return false; | ||||||
| 		                    UInfo.webtoken = UInfo2.webtoken; |                 auto now=OpenWifi::Now(); | ||||||
| 		                    UserCache_.update(CallToken, UInfo); |                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||||
| 		                    SessionToken = CallToken; |                 if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) { | ||||||
| 		                    return true; |                     UInfo.webtoken = WT; | ||||||
| 		                } |                     SessionToken = CallToken; | ||||||
| 		            } |                     return true; | ||||||
| 		            return false; |                 } | ||||||
| 		        } |             } | ||||||
| 		        if(!Expired) { |             return false; | ||||||
| 		            SessionToken = CallToken; |  | ||||||
| 		            UInfo = *Client ; |  | ||||||
| 		            return true; |  | ||||||
| 		        } |  | ||||||
|                 RevokeToken(CallToken); |  | ||||||
| 		        return false; |  | ||||||
| 		    } |  | ||||||
| 		} catch(const Poco::Exception &E) { | 		} catch(const Poco::Exception &E) { | ||||||
| 		    Logger_.log(E); | 		    Logger().log(E); | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AuthService::RevokeToken(std::string & Token) { |     bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||||
|         UserCache_.remove(Token); |     { | ||||||
|         StorageService()->RevokeToken(Token); |         std::lock_guard	Guard(Mutex_); | ||||||
|  |         Expired = false; | ||||||
|  |         try { | ||||||
|  |             std::string CallToken; | ||||||
|  |             Poco::Net::OAuth20Credentials Auth(Request); | ||||||
|  |             if (Auth.getScheme() == "Bearer") { | ||||||
|  |                 CallToken = Auth.getBearerToken(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(CallToken.empty()) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             SecurityObjects::WebToken   WT; | ||||||
|  |             uint64_t                    RevocationDate=0; | ||||||
|  |             std::string                 UserId; | ||||||
|  |             if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||||
|  |                 if(RevocationDate!=0) | ||||||
|  |                     return false; | ||||||
|  |                 auto now=OpenWifi::Now(); | ||||||
|  |                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||||
|  |                 if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) { | ||||||
|  |                     UInfo.webtoken = WT; | ||||||
|  |                     SessionToken = CallToken; | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } catch(const Poco::Exception &E) { | ||||||
|  |             Logger().log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::DeleteUserFromCache(const std::string &UserName) { |     void AuthService::RevokeToken(std::string & Token) { | ||||||
|         std::lock_guard		Guard(Mutex_); |         StorageService()->UserTokenDB().RevokeToken(Token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         std::vector<std::string>    OldTokens; |     void AuthService::RevokeSubToken(std::string & Token) { | ||||||
|  |         StorageService()->SubTokenDB().RevokeToken(Token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void |     bool AuthService::DeleteUserFromCache(const std::string &Id) { | ||||||
|         { if(O.userinfo.email==UserName) |         return StorageService()->UserTokenDB().DeleteRecordsFromCache("userName",Id); | ||||||
|             OldTokens.push_back(token); |     } | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         for(const auto &i:OldTokens) { |     bool AuthService::DeleteSubUserFromCache(const std::string &Id) { | ||||||
|             Logout(i,false); |         return StorageService()->SubTokenDB().DeleteRecordsFromCache("userName",Id); | ||||||
|             UserCache_.remove(i); |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) { |     bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||||
|         return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer().MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method)); |         return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer::MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::ValidatePassword(const std::string &Password) { |     bool AuthService::ValidatePassword(const std::string &Password) { | ||||||
|         return std::regex_match(Password, PasswordValidation_); |         return std::regex_match(Password, PasswordValidation_); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AuthService::Logout(const std::string &token, bool EraseFromCache) { |     bool AuthService::ValidateSubPassword(const std::string &Password) { | ||||||
| 		std::lock_guard		Guard(Mutex_); |         return std::regex_match(Password, SubPasswordValidation_); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AuthService::RemoveTokenSystemWide(const std::string &token) { | ||||||
|         try { |         try { | ||||||
|             Poco::JSON::Object Obj; |             if(KafkaManager()->Enabled()) { | ||||||
|             Obj.set("event", "remove-token"); |                 Poco::JSON::Object Obj; | ||||||
|             Obj.set("id", MicroService::instance().ID()); |                 Obj.set("event", "remove-token"); | ||||||
|             Obj.set("token", token); |                 Obj.set("id", MicroService::instance().ID()); | ||||||
|             std::stringstream ResultText; |                 Obj.set("token", token); | ||||||
|             Poco::JSON::Stringifier::stringify(Obj, ResultText); |                 std::stringstream ResultText; | ||||||
|             std::string Tmp{token}; |                 Poco::JSON::Stringifier::stringify(Obj, ResultText); | ||||||
|             RevokeToken(Tmp); |                 KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), | ||||||
|             KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), |                                             ResultText.str(), | ||||||
|                                         false); |                                             false); | ||||||
|  |             } | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|             Logger_.log(E); |             Logger().log(E); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { |     void AuthService::Logout(const std::string &Token,[[maybe_unused]]  bool EraseFromCache) { | ||||||
|         std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand())); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             auto tToken{Token}; | ||||||
|  |             StorageService()->UserTokenDB().DeleteRecord("token",tToken); | ||||||
|  |             StorageService()->LoginDB().AddLogout(Token); | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger().log(E); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AuthService::SubLogout(const std::string &Token, [[maybe_unused]] bool EraseFromCache) { | ||||||
|  |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             auto tToken{Token}; | ||||||
|  |             StorageService()->SubTokenDB().DeleteRecord("token",tToken); | ||||||
|  |             StorageService()->SubLoginDB().AddLogout(Token); | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger().log(E); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [[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); |         HMAC_.update(Identity); | ||||||
|         return Poco::DigestEngine::digestToHex(HMAC_.digest()); |         return Poco::DigestEngine::digestToHex(HMAC_.digest()); | ||||||
|     } |     } | ||||||
| @@ -169,7 +305,7 @@ namespace OpenWifi { | |||||||
| 		T.payload().set("identity", Identity); | 		T.payload().set("identity", Identity); | ||||||
| 		T.setIssuedAt(Poco::Timestamp()); | 		T.setIssuedAt(Poco::Timestamp()); | ||||||
| 		T.setExpiration(Poco::Timestamp() + (long long)TokenAging_); | 		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; | 		return JWT; | ||||||
|     } |     } | ||||||
| @@ -184,18 +320,42 @@ namespace OpenWifi { | |||||||
|         UInfo.webtoken.expires_in_ = TokenAging_ ; |         UInfo.webtoken.expires_in_ = TokenAging_ ; | ||||||
|         UInfo.webtoken.idle_timeout_ = 5 * 60; |         UInfo.webtoken.idle_timeout_ = 5 * 60; | ||||||
|         UInfo.webtoken.token_type_ = "Bearer"; |         UInfo.webtoken.token_type_ = "Bearer"; | ||||||
|         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); |         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); | ||||||
|         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); |         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); | ||||||
|         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,CUSTOM); |         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM); | ||||||
|         UInfo.webtoken.created_ = time(nullptr); |         UInfo.webtoken.created_ = time(nullptr); | ||||||
|         UInfo.webtoken.username_ = UserName; |         UInfo.webtoken.username_ = UserName; | ||||||
|         UInfo.webtoken.errorCode = 0; |         UInfo.webtoken.errorCode = 0; | ||||||
|         UInfo.webtoken.userMustChangePassword = false; |         UInfo.webtoken.userMustChangePassword = false; | ||||||
|         UserCache_.update(UInfo.webtoken.access_token_,UInfo); |         StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); | ||||||
|         StorageService()->SetLastLogin(UInfo.userinfo.Id); |         StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_, | ||||||
|         StorageService()->AddToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_, |  | ||||||
|                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, |                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, | ||||||
|                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); |                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); | ||||||
|  |         StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) | ||||||
|  |     { | ||||||
|  |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|  |         SecurityObjects::AclTemplate	ACL; | ||||||
|  |         ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true; | ||||||
|  |         UInfo.webtoken.acl_template_ = ACL; | ||||||
|  |         UInfo.webtoken.expires_in_ = TokenAging_ ; | ||||||
|  |         UInfo.webtoken.idle_timeout_ = 5 * 60; | ||||||
|  |         UInfo.webtoken.token_type_ = "Bearer"; | ||||||
|  |         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); | ||||||
|  |         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); | ||||||
|  |         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM); | ||||||
|  |         UInfo.webtoken.created_ = time(nullptr); | ||||||
|  |         UInfo.webtoken.username_ = UserName; | ||||||
|  |         UInfo.webtoken.errorCode = 0; | ||||||
|  |         UInfo.webtoken.userMustChangePassword = false; | ||||||
|  |         StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); | ||||||
|  |         StorageService()->SubTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_, | ||||||
|  |                                    UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, | ||||||
|  |                                    UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); | ||||||
|  |         StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { |     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { | ||||||
| @@ -232,6 +392,40 @@ namespace OpenWifi { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { | ||||||
|  |         std::lock_guard     G(Mutex_); | ||||||
|  |  | ||||||
|  |         Poco::toLowerInPlace(UInfo.email); | ||||||
|  |         for (const auto &i:UInfo.lastPasswords) { | ||||||
|  |             auto Tokens = Poco::StringTokenizer(i,"|"); | ||||||
|  |             if(Tokens.count()==2) { | ||||||
|  |                 const auto & Salt = Tokens[0]; | ||||||
|  |                 for(const auto &j:UInfo.lastPasswords) { | ||||||
|  |                     auto OldTokens = Poco::StringTokenizer(j,"|"); | ||||||
|  |                     if(OldTokens.count()==2) { | ||||||
|  |                         SHA2_.update(Salt+NewPassword+UInfo.email); | ||||||
|  |                         if(OldTokens[1]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                             return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 SHA2_.update(NewPassword+UInfo.email); | ||||||
|  |                 if(Tokens[0]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                     return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(UInfo.lastPasswords.size()==HowManyOldPassword_) { | ||||||
|  |             UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword); | ||||||
|  |         UInfo.lastPasswords.push_back(NewHash); | ||||||
|  |         UInfo.currentPassword = NewHash; | ||||||
|  |         UInfo.changePassword = false; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     static std::string GetMeSomeSalt() { |     static std::string GetMeSomeSalt() { | ||||||
|         auto start = std::chrono::high_resolution_clock::now(); |         auto start = std::chrono::high_resolution_clock::now(); | ||||||
|         return std::to_string(start.time_since_epoch().count()); |         return std::to_string(start.time_since_epoch().count()); | ||||||
| @@ -261,13 +455,30 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) |     bool AuthService::ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) { | ||||||
|  |         std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|  |         std::string UName = Poco::trim(Poco::toLower(UserName)); | ||||||
|  |         auto Tokens = Poco::StringTokenizer(StoredPassword,"|"); | ||||||
|  |         if(Tokens.count()==1) { | ||||||
|  |             SHA2_.update(Password+UName); | ||||||
|  |             if(Tokens[0]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                 return true; | ||||||
|  |         } else if (Tokens.count()==2) { | ||||||
|  |             SHA2_.update(Tokens[0]+Password+UName); | ||||||
|  |             if(Tokens[1]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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_); |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UserName); |         Poco::toLowerInPlace(UserName); | ||||||
|  |  | ||||||
|         if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { |         if(StorageService()->UserDB().GetUserByEmail(UserName,UInfo.userinfo)) { | ||||||
|             if(UInfo.userinfo.waitingForEmailCheck) { |             if(UInfo.userinfo.waitingForEmailCheck) { | ||||||
|                 return USERNAME_PENDING_VERIFICATION; |                 return USERNAME_PENDING_VERIFICATION; | ||||||
|             } |             } | ||||||
| @@ -290,14 +501,15 @@ namespace OpenWifi { | |||||||
|                     UInfo.webtoken.errorCode = 1; |                     UInfo.webtoken.errorCode = 1; | ||||||
|                     return PASSWORD_ALREADY_USED; |                     return PASSWORD_ALREADY_USED; | ||||||
|                 } |                 } | ||||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); |                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||||
|                 UInfo.userinfo.changePassword = false; |                 UInfo.userinfo.changePassword = false; | ||||||
|                 StorageService()->UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.Id,UInfo.userinfo); |                 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. |             //  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()->SetLastLogin(UInfo.userinfo.Id); |             StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); | ||||||
|             CreateToken(UserName, UInfo ); |             CreateToken(UserName, UInfo ); | ||||||
|  |  | ||||||
|             return SUCCESS; |             return SUCCESS; | ||||||
| @@ -306,10 +518,56 @@ namespace OpenWifi { | |||||||
|         return INVALID_CREDENTIALS; |         return INVALID_CREDENTIALS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     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_); | ||||||
|  |  | ||||||
|  |         Poco::toLowerInPlace(UserName); | ||||||
|  |  | ||||||
|  |         if(StorageService()->SubDB().GetUserByEmail(UserName,UInfo.userinfo)) { | ||||||
|  |             if(UInfo.userinfo.waitingForEmailCheck) { | ||||||
|  |                 return USERNAME_PENDING_VERIFICATION; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(!ValidateSubPasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) { | ||||||
|  |                 return INVALID_CREDENTIALS; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(UInfo.userinfo.changePassword && NewPassword.empty()) { | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true ; | ||||||
|  |                 return PASSWORD_CHANGE_REQUIRED; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(!NewPassword.empty() && !ValidateSubPassword(NewPassword)) { | ||||||
|  |                 return PASSWORD_INVALID; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(UInfo.userinfo.changePassword || !NewPassword.empty()) { | ||||||
|  |                 if(!SetSubPassword(NewPassword,UInfo.userinfo)) { | ||||||
|  |                     UInfo.webtoken.errorCode = 1; | ||||||
|  |                     return PASSWORD_ALREADY_USED; | ||||||
|  |                 } | ||||||
|  |                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||||
|  |                 UInfo.userinfo.changePassword = false; | ||||||
|  |                 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=OpenWifi::Now(); | ||||||
|  |             StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); | ||||||
|  |             CreateSubToken(UserName, UInfo ); | ||||||
|  |  | ||||||
|  |             return SUCCESS; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return INVALID_CREDENTIALS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { |     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         if(StorageService()->GetUserByEmail(Email,UInfo)) { |         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { | ||||||
|             switch (Reason) { |             switch (Reason) { | ||||||
|  |  | ||||||
|                 case FORGOT_PASSWORD: { |                 case FORGOT_PASSWORD: { | ||||||
| @@ -326,7 +584,7 @@ namespace OpenWifi { | |||||||
|                         MessageAttributes Attrs; |                         MessageAttributes Attrs; | ||||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; |                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                         Attrs[LOGO] = GetLogoAssetURI(); |                         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 ; |                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||||
|                         UInfo.waitingForEmailCheck = true; |                         UInfo.waitingForEmailCheck = true; | ||||||
| @@ -341,52 +599,121 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { |     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||||
|         SecurityObjects::ActionLink A; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; |         if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) { | ||||||
|         A.userId = UInfo.email; |             switch (Reason) { | ||||||
|         A.id = MicroService::CreateUUID(); |  | ||||||
|         A.created = std::time(nullptr); |  | ||||||
|         A.expires = A.created + 24*60*60; |  | ||||||
|         StorageService()->CreateAction(A); |  | ||||||
|         UInfo.waitingForEmailCheck = true; |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { |                 case FORGOT_PASSWORD: { | ||||||
|         std::lock_guard G(Mutex_); |                     MessageAttributes Attrs; | ||||||
|  |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|  |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|  |                     Attrs[SUBJECT] = "Password reset link"; | ||||||
|  |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||||
|  |                     SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|         Expired = false; |                 case EMAIL_VERIFICATION: { | ||||||
|  |                     MessageAttributes Attrs; | ||||||
|  |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|  |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|  |                     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; | ||||||
|  |  | ||||||
|         auto Client = UserCache_.get(Token); |                 case SIGNUP_VERIFICATION: { | ||||||
|         if(!Client.isNull()) { |                     MessageAttributes Attrs; | ||||||
|             Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr); |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|             WebToken = Client->webtoken; |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|             UserInfo = Client->userinfo; |                     Attrs[SUBJECT] = "Signup e-mail Address Verification"; | ||||||
|             return true; |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ; | ||||||
|         } |                     SMTPMailerService()->SendMessage(UInfo.email, "signup_verification.txt", Attrs); | ||||||
|  |                     UInfo.waitingForEmailCheck = true; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|         std::string TToken{Token}; |                 default: | ||||||
|         if(StorageService()->IsTokenRevoked(TToken)) { |                     break; | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         //  get the token from disk... |  | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|         uint64_t RevocationDate=0; |  | ||||||
|         if(StorageService()->GetToken(TToken, UInfo, RevocationDate)) { |  | ||||||
|             if(RevocationDate!=0) |  | ||||||
|                 return false; |  | ||||||
|             Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr); |  | ||||||
|             if(StorageService()->GetUserById(UInfo.userinfo.Id,UInfo.userinfo)) { |  | ||||||
|                 WebToken = UInfo.webtoken; |  | ||||||
|                 UserCache_.update(UInfo.webtoken.access_token_, UInfo); |  | ||||||
|                 return true; |  | ||||||
|             } |             } | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { | ||||||
|  |         SecurityObjects::ActionLink A; | ||||||
|  |  | ||||||
|  |         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; | ||||||
|  |         A.userId = UInfo.id; | ||||||
|  |         A.id = MicroService::CreateUUID(); | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::VerifySubEmail(SecurityObjects::UserInfo &UInfo) { | ||||||
|  |         SecurityObjects::ActionLink A; | ||||||
|  |  | ||||||
|  |         A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL; | ||||||
|  |         A.userId = UInfo.id; | ||||||
|  |         A.id = MicroService::CreateUUID(); | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { | ||||||
|  |  | ||||||
|  |         std::lock_guard G(Mutex_); | ||||||
|  |         Expired = false; | ||||||
|  |  | ||||||
|  |         std::string TToken{Token}, UserId; | ||||||
|  |         SecurityObjects::WebToken   WT; | ||||||
|  |         uint64_t RevocationDate=0; | ||||||
|  |         if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||||
|  |             if(RevocationDate!=0) | ||||||
|  |                 return false; | ||||||
|  |             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||||
|  |             if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) { | ||||||
|  |                 WebToken = WT; | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return IsValidSubToken(Token, WebToken, UserInfo, Expired); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { | ||||||
|  |         std::lock_guard G(Mutex_); | ||||||
|  |         Expired = false; | ||||||
|  |  | ||||||
|  |         std::string TToken{Token}, UserId; | ||||||
|  |         SecurityObjects::WebToken   WT; | ||||||
|  |         uint64_t RevocationDate=0; | ||||||
|  |         if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||||
|  |             if(RevocationDate!=0) | ||||||
|  |                 return false; | ||||||
|  |             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||||
|  |             if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) { | ||||||
|  |                 WebToken = WT; | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
| }  // end of namespace | }  // end of namespace | ||||||
|   | |||||||
| @@ -38,14 +38,15 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|         enum EMAIL_REASON { |         enum EMAIL_REASON { | ||||||
|             FORGOT_PASSWORD, |             FORGOT_PASSWORD, | ||||||
|             EMAIL_VERIFICATION |             EMAIL_VERIFICATION, | ||||||
|  |             SIGNUP_VERIFICATION | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         static ACCESS_TYPE IntToAccessType(int C); |         static ACCESS_TYPE IntToAccessType(int C); | ||||||
|         static int AccessTypeToInt(ACCESS_TYPE T); |         static int AccessTypeToInt(ACCESS_TYPE T); | ||||||
|  |  | ||||||
|         static AuthService *instance() { |         static auto instance() { | ||||||
|             static auto * instance_ = new AuthService; |             static auto instance_ = new AuthService; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -59,23 +60,44 @@ namespace OpenWifi{ | |||||||
|         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; |         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||||
|         void Logout(const std::string &token, bool EraseFromCache=true); |         void Logout(const std::string &token, bool EraseFromCache=true); | ||||||
|  |  | ||||||
|  |         [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); | ||||||
|  |         [[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||||
|  |         void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|  |         [[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); | ||||||
|  |         [[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||||
|  |         void SubLogout(const std::string &token, bool EraseFromCache=true); | ||||||
|  |  | ||||||
|  |         void RemoveTokenSystemWide(const std::string &token); | ||||||
|  |  | ||||||
|         bool ValidatePassword(const std::string &pwd); |         bool ValidatePassword(const std::string &pwd); | ||||||
|  |         bool ValidateSubPassword(const std::string &pwd); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); |         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); | ||||||
|  |         [[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); | ||||||
|         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|  |  | ||||||
|         [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); |         [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); | ||||||
|         [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); |         [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); | ||||||
|  |         [[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); |         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); | ||||||
|         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); |         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); | ||||||
|  |  | ||||||
|  |         [[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); | ||||||
|  |         [[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName); | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); |         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|  |         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||||
|         [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); |         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); |         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|  |  | ||||||
|  |         bool DeleteUserFromCache(const std::string &UserName); | ||||||
|  |         bool DeleteSubUserFromCache(const std::string &UserName); | ||||||
|         void RevokeToken(std::string & Token); |         void RevokeToken(std::string & Token); | ||||||
|  |         void RevokeSubToken(std::string & Token); | ||||||
|  |  | ||||||
|         [[nodiscard]] static inline const std::string GetLogoAssetURI() { |         [[nodiscard]] static inline const std::string GetLogoAssetURI() { | ||||||
|             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; |             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; | ||||||
| @@ -85,15 +107,30 @@ namespace OpenWifi{ | |||||||
|             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; |             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; } | ||||||
|  |         inline const std::string & GetAccessPolicy() const { return AccessPolicy_; } | ||||||
|  |  | ||||||
|  |         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: |     private: | ||||||
| 		Poco::JWT::Signer	Signer_; |  | ||||||
| 		Poco::SHA2Engine	SHA2_; | 		Poco::SHA2Engine	SHA2_; | ||||||
| 		Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy>    UserCache_{2048,1200000}; |  | ||||||
| 		// SecurityObjects::UserInfoCache UserCache_; | 		std::string         AccessPolicy_; | ||||||
|         std::string         PasswordValidationStr_; | 		std::string         PasswordPolicy_; | ||||||
| 		std::regex          PasswordValidation_; | 		std::string         SubAccessPolicy_; | ||||||
| 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | 		std::string         SubPasswordPolicy_; | ||||||
|  | 		std::string         PasswordValidationStr_; | ||||||
|  |         std::string         SubPasswordValidationStr_; | ||||||
|  |         std::regex          PasswordValidation_; | ||||||
|  |         std::regex          SubPasswordValidation_; | ||||||
|  |  | ||||||
|  |         uint64_t            TokenAging_ = 15 * 24 * 60 * 60; | ||||||
|         uint64_t            HowManyOldPassword_=5; |         uint64_t            HowManyOldPassword_=5; | ||||||
|  |         uint64_t            RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ; | ||||||
|  |  | ||||||
|         class SHA256Engine : public Poco::Crypto::DigestEngine |         class SHA256Engine : public Poco::Crypto::DigestEngine | ||||||
|                 { |                 { | ||||||
| @@ -119,10 +156,13 @@ namespace OpenWifi{ | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline AuthService * AuthService() { return AuthService::instance(); } |     inline auto AuthService() { return AuthService::instance(); } | ||||||
|  |  | ||||||
|     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) { |     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) { | ||||||
|         return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); |         if(Sub) | ||||||
|  |             return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired ); | ||||||
|  |         else | ||||||
|  |             return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } // end of namespace | } // end of namespace | ||||||
|   | |||||||
| @@ -10,8 +10,6 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #include <cstdlib> |  | ||||||
| #include <boost/algorithm/string.hpp> |  | ||||||
|  |  | ||||||
| #include "Poco/Util/Application.h" | #include "Poco/Util/Application.h" | ||||||
| #include "Poco/Util/Option.h" | #include "Poco/Util/Option.h" | ||||||
| @@ -20,17 +18,14 @@ | |||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
|  |  | ||||||
| #include <aws/core/Aws.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/AccessControlPolicy.h> | ||||||
| #include <aws/s3/model/PutBucketAclRequest.h> |  | ||||||
| #include <aws/s3/model/GetBucketAclRequest.h> |  | ||||||
|  |  | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
| #include "ActionLinkManager.h" | #include "ActionLinkManager.h" | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class Daemon *Daemon::instance_ = nullptr; |     class Daemon *Daemon::instance_ = nullptr; | ||||||
| @@ -48,20 +43,15 @@ namespace OpenWifi { | |||||||
|                                            ActionLinkManager(), |                                            ActionLinkManager(), | ||||||
|                                            SMTPMailerService(), |                                            SMTPMailerService(), | ||||||
|                                            RESTAPI_RateLimiter(), |                                            RESTAPI_RateLimiter(), | ||||||
|  |                                            TotpCache(), | ||||||
|                                            AuthService() |                                            AuthService() | ||||||
|                                    }); |                                    }); | ||||||
|         } |         } | ||||||
|         return instance_; |         return instance_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Daemon::initialize() { |     void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { | ||||||
|         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); |         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); | ||||||
|         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); |  | ||||||
|         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void MicroServicePostInitialization() { |  | ||||||
|         Daemon()->initialize(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/Daemon.h
									
									
									
									
									
								
							| @@ -20,16 +20,15 @@ | |||||||
| #include "Poco/Crypto/CipherFactory.h" | #include "Poco/Crypto/CipherFactory.h" | ||||||
| #include "Poco/Crypto/Cipher.h" | #include "Poco/Crypto/Cipher.h" | ||||||
|  |  | ||||||
| #include "framework/OpenWifiTypes.h" |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; |     [[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; | ||||||
|     static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; |     [[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; | ||||||
|     static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; |     [[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; | ||||||
|     static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); |     [[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); | ||||||
|     static const uint64_t vDAEMON_BUS_TIMER = 5000; |     [[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000; | ||||||
|  |  | ||||||
|     class Daemon : public MicroService { |     class Daemon : public MicroService { | ||||||
|     public: |     public: | ||||||
| @@ -41,19 +40,18 @@ namespace OpenWifi { | |||||||
|                         const SubSystemVec & SubSystems) : |                         const SubSystemVec & SubSystems) : | ||||||
|                 MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; |                 MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; | ||||||
|  |  | ||||||
|         void initialize(); |         void PostInitialization(Poco::Util::Application &self); | ||||||
|         static Daemon *instance(); |         static Daemon *instance(); | ||||||
|         inline const std::string & AssetDir() { return AssetDir_; } |         inline const std::string & AssetDir() { return AssetDir_; } | ||||||
|         inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; } |  | ||||||
|         inline const std::string & GetAccessPolicy() const { return AccessPolicy_; } |  | ||||||
|     private: |     private: | ||||||
|         static Daemon 		*instance_; |         static Daemon 		*instance_; | ||||||
|         std::string         AssetDir_; |         std::string         AssetDir_; | ||||||
|         std::string         PasswordPolicy_; |  | ||||||
|         std::string         AccessPolicy_; |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline Daemon * Daemon() { return Daemon::instance(); } |     inline Daemon * Daemon() { return Daemon::instance(); } | ||||||
|  |     inline void DaemonPostInitialization(Poco::Util::Application &self) { | ||||||
|  |         Daemon()->PostInitialization(self); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //UCENTRALSEC_DAEMON_H | #endif //UCENTRALSEC_DAEMON_H | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -27,10 +28,11 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         std::string Challenge = MakeChallenge(); |         std::string Challenge = MakeChallenge(); | ||||||
|         std::string uuid = MicroService::CreateUUID(); |         std::string uuid = MicroService::CreateUUID(); | ||||||
|         uint64_t Created = std::time(nullptr); |         uint64_t Created = OpenWifi::Now(); | ||||||
|  |  | ||||||
|         ChallengeStart.set("uuid",uuid); |         ChallengeStart.set("uuid",uuid); | ||||||
|         ChallengeStart.set("created", Created); |         ChallengeStart.set("created", Created); | ||||||
|  |         ChallengeStart.set("question", "mfa challenge"); | ||||||
|         ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method); |         ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method); | ||||||
|  |  | ||||||
|         Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method }; |         Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method }; | ||||||
| @@ -38,18 +40,18 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) { |     bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) { | ||||||
|         if(Method=="sms" && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) { |         if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) { | ||||||
|             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; |             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; | ||||||
|             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); |             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); | ||||||
|         } |         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||||
|  |  | ||||||
|         if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { |  | ||||||
|             MessageAttributes Attrs; |             MessageAttributes Attrs; | ||||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; |             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); |             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||||
|             Attrs[SUBJECT] = "Login validation code"; |             Attrs[SUBJECT] = "Login validation code"; | ||||||
|             Attrs[CHALLENGE_CODE] = Challenge; |             Attrs[CHALLENGE_CODE] = Challenge; | ||||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); |             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); | ||||||
|  |         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
| @@ -63,7 +65,7 @@ namespace OpenWifi { | |||||||
|         return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer); |         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_); |         std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|         if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer")) |         if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer")) | ||||||
| @@ -76,7 +78,12 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         auto answer = ChallengeResponse->get("answer").toString(); |         auto answer = ChallengeResponse->get("answer").toString(); | ||||||
|         if(Hint->second.Answer!=answer) { |         std::string Expecting; | ||||||
|  |         if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) { | ||||||
|  |             if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } else if(Hint->second.Answer!=answer) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -86,18 +93,21 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAServer::MethodEnabled(const std::string &Method) { |     bool MFAServer::MethodEnabled(const std::string &Method) { | ||||||
|         if(Method=="sms") |         if(Method==MFAMETHODS::SMS) | ||||||
|             return SMSSender()->Enabled(); |             return SMSSender()->Enabled(); | ||||||
|  |  | ||||||
|         if(Method=="email") |         if(Method==MFAMETHODS::EMAIL) | ||||||
|             return SMTPMailerService()->Enabled(); |             return SMTPMailerService()->Enabled(); | ||||||
|  |  | ||||||
|  |         if(Method==MFAMETHODS::AUTHENTICATOR) | ||||||
|  |             return true; | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void MFAServer::CleanCache() { |     void MFAServer::CleanCache() { | ||||||
|         // it is assumed that you have locked Cache_ at this point. |         // 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_);) { |         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||||
|             if((Now-i->second.Created)>300) { |             if((Now-i->second.Created)>300) { | ||||||
|                 i = Cache_.erase(i); |                 i = Cache_.erase(i); | ||||||
|   | |||||||
| @@ -2,14 +2,24 @@ | |||||||
| // Created by stephane bourque on 2021-10-11. | // Created by stephane bourque on 2021-10-11. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef OWSEC_MFASERVER_H | #pragma once | ||||||
| #define OWSEC_MFASERVER_H |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     namespace MFAMETHODS { | ||||||
|  |         inline const static std::string SMS{"sms"}; | ||||||
|  |         inline const static std::string EMAIL{"email"}; | ||||||
|  |         inline const static std::string AUTHENTICATOR{"authenticator"}; | ||||||
|  |         inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR }; | ||||||
|  |         inline bool Validate(const std::string &M) { | ||||||
|  |             return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     struct MFACacheEntry { |     struct MFACacheEntry { | ||||||
|         SecurityObjects::UserInfoAndPolicy  UInfo; |         SecurityObjects::UserInfoAndPolicy  UInfo; | ||||||
|         std::string                         Answer; |         std::string                         Answer; | ||||||
| @@ -17,25 +27,26 @@ namespace OpenWifi { | |||||||
|         std::string                         Method; |         std::string                         Method; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|     typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache; |     typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache; | ||||||
|  |  | ||||||
|     class MFAServer : public SubSystemServer{ |     class MFAServer : public SubSystemServer{ | ||||||
|     public: |     public: | ||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|         static MFAServer *instance() { |         static auto instance() { | ||||||
|             static auto * instance_ = new MFAServer; |             static auto instance_ = new MFAServer; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); |         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); |         static bool MethodEnabled(const std::string &Method); | ||||||
|         bool ResendCode(const std::string &uuid); |         bool ResendCode(const std::string &uuid); | ||||||
|         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); |         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||||
|  |  | ||||||
|         static inline std::string MakeChallenge() { |         static inline std::string MakeChallenge() { | ||||||
|             return std::to_string(MicroService::instance().Random(1,999999)); |             return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
| @@ -48,7 +59,6 @@ namespace OpenWifi { | |||||||
|         void CleanCache(); |         void CleanCache(); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline MFAServer & MFAServer() { return *MFAServer::instance(); } |     inline auto MFAServer() { return MFAServer::instance(); } | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OWSEC_MFASERVER_H |  | ||||||
|   | |||||||
| @@ -18,13 +18,15 @@ namespace OpenWifi { | |||||||
|         auto Id = GetParameter("id",""); |         auto Id = GetParameter("id",""); | ||||||
|  |  | ||||||
|         SecurityObjects::ActionLink Link; |         SecurityObjects::ActionLink Link; | ||||||
|         if(!StorageService()->GetActionLink(Id,Link)) |         if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             return RequestResetPassword(Link); |             return RequestResetPassword(Link); | ||||||
|         else if(Action=="email_verification") |         else if(Action=="email_verification") | ||||||
|             return DoEmailVerification(Link); |             return DoEmailVerification(Link); | ||||||
|  |         else if(Action=="signup_verification") | ||||||
|  |             return DoNewSubVerification(Link); | ||||||
|         else |         else | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|     } |     } | ||||||
| @@ -34,18 +36,28 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             return CompleteResetPassword(); |             return CompleteResetPassword(); | ||||||
|  |         else if(Action=="signup_completion") | ||||||
|  |             return CompleteSubVerification(); | ||||||
|         else |         else | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) { |     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"}; |         Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; | ||||||
|         Types::StringPairVec    FormVars{ {"UUID", Link.id}, |         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; |                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||||
|         SendHTMLFileBack(FormFile,FormVars); |         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() { |     void RESTAPI_action_links::CompleteResetPassword() { | ||||||
|         //  form has been posted... |         //  form has been posted... | ||||||
|         RESTAPI_PartHandler PartHandler; |         RESTAPI_PartHandler PartHandler; | ||||||
| @@ -53,16 +65,16 @@ namespace OpenWifi { | |||||||
|         if (!Form.empty()) { |         if (!Form.empty()) { | ||||||
|  |  | ||||||
|             auto Password1 = Form.get("password1","bla"); |             auto Password1 = Form.get("password1","bla"); | ||||||
|             auto Password2 = Form.get("password1","blu"); |             auto Password2 = Form.get("password2","blu"); | ||||||
|             auto Id = Form.get("id",""); |             auto Id = Form.get("id",""); | ||||||
|             auto Now = std::time(nullptr); |             auto now = OpenWifi::Now(); | ||||||
|  |  | ||||||
|             SecurityObjects::ActionLink Link; |             SecurityObjects::ActionLink Link; | ||||||
|             if(!StorageService()->GetActionLink(Id,Link)) |             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) | ||||||
|                 return DoReturnA404(); |                 return DoReturnA404(); | ||||||
|  |  | ||||||
|             if(Now > Link.expires) { |             if(now > Link.expires) { | ||||||
|                 StorageService()->CancelAction(Id); |                 StorageService()->ActionLinksDB().CancelAction(Id); | ||||||
|                 return DoReturnA404(); |                 return DoReturnA404(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -77,7 +89,9 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             SecurityObjects::UserInfo   UInfo; |             SecurityObjects::UserInfo   UInfo; | ||||||
|             if(!StorageService()->GetUserById(Link.userId,UInfo)) { |  | ||||||
|  |             bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo); | ||||||
|  |             if(!Found) { | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; |                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; | ||||||
| @@ -91,51 +105,154 @@ namespace OpenWifi { | |||||||
|                 return SendHTMLFileBack(FormFile,FormVars); |                 return SendHTMLFileBack(FormFile,FormVars); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(!AuthService()->SetPassword(Password1,UInfo)) { |             bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo); | ||||||
|  |             if(!GoodPassword) { | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; |                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; | ||||||
|                 return SendHTMLFileBack(FormFile,FormVars); |                 return SendHTMLFileBack(FormFile,FormVars); | ||||||
|             } |             } | ||||||
|             StorageService()->UpdateUserInfo(UInfo.email,Link.userId,UInfo); |  | ||||||
|  |             UInfo.modified = OpenWifi::Now(); | ||||||
|  |             if(Link.userAction) | ||||||
|  |                 StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||||
|  |             else | ||||||
|  |                 StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||||
|  |  | ||||||
|             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; |             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; | ||||||
|             Types::StringPairVec    FormVars{ {"UUID", Id}, |             Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                               {"USERNAME", UInfo.email}, |                                               {"USERNAME", UInfo.email}, | ||||||
|                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|             StorageService()->CompleteAction(Id); |             StorageService()->ActionLinksDB().CompleteAction(Id); | ||||||
|             SendHTMLFileBack(FormFile,FormVars); |             SendHTMLFileBack(FormFile,FormVars); | ||||||
|         } else { |         } else { | ||||||
|             DoReturnA404(); |             DoReturnA404(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) { |     void RESTAPI_action_links::CompleteSubVerification() { | ||||||
|         auto Now = std::time(nullptr); |         RESTAPI_PartHandler PartHandler; | ||||||
|  |         Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); | ||||||
|  |  | ||||||
|         if(Now > Link.expires) { |         if (!Form.empty()) { | ||||||
|             StorageService()->CancelAction(Link.id); |             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(); |             return DoReturnA404(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
|         if (!StorageService()->GetUserById(Link.userId, UInfo)) { |         bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo); | ||||||
|  |         if (!Found) { | ||||||
|             Types::StringPairVec FormVars{{"UUID",       Link.id}, |             Types::StringPairVec FormVars{{"UUID",       Link.id}, | ||||||
|                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; |                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; | ||||||
|             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; |             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; | ||||||
|             return SendHTMLFileBack(FormFile, FormVars); |             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.waitingForEmailCheck = false; | ||||||
|         UInfo.validated = true; |         UInfo.validated = true; | ||||||
|         UInfo.lastEmailCheck = std::time(nullptr); |         UInfo.lastEmailCheck = OpenWifi::Now(); | ||||||
|         UInfo.validationDate = std::time(nullptr); |         UInfo.validationDate = OpenWifi::Now(); | ||||||
|         StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo); |         UInfo.modified  = OpenWifi::Now(); | ||||||
|  |         if(Link.userAction) | ||||||
|  |             StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||||
|  |         else | ||||||
|  |             StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||||
|         Types::StringPairVec FormVars{{"UUID",     Link.id}, |         Types::StringPairVec FormVars{{"UUID",     Link.id}, | ||||||
|                                       {"USERNAME", UInfo.email}, |                                       {"USERNAME", UInfo.email}, | ||||||
|                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; |         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; | ||||||
|         StorageService()->CompleteAction(Link.id); |         StorageService()->ActionLinksDB().CompleteAction(Link.id); | ||||||
|         SendHTMLFileBack(FormFile, FormVars); |         SendHTMLFileBack(FormFile, FormVars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,30 +2,31 @@ | |||||||
| // Created by stephane bourque on 2021-06-22. | // Created by stephane bourque on 2021-06-22. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef UCENTRALSEC_RESTAPI_ACTION_LINKS_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_ACTION_LINKS_H |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_action_links : public RESTAPIHandler { |     class RESTAPI_action_links : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|              std::vector<std::string>{ |              std::vector<std::string>{ | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_GET, |                                         Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_POST, |                                         Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                         Server, |                                         Server, | ||||||
|  |                                         TransactionId, | ||||||
|                                         Internal, |                                         Internal, | ||||||
|                                         false, |                                         false, | ||||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} |                                         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 RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||||
|         void CompleteResetPassword(); |         void CompleteResetPassword(); | ||||||
|  |         void CompleteSubVerification(); | ||||||
|         void DoEmailVerification(SecurityObjects::ActionLink &Link); |         void DoEmailVerification(SecurityObjects::ActionLink &Link); | ||||||
|         void DoReturnA404(); |         void DoReturnA404(); | ||||||
|  |         void DoNewSubVerification(SecurityObjects::ActionLink &Link); | ||||||
|  |  | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
| @@ -33,5 +34,3 @@ namespace OpenWifi { | |||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //UCENTRALSEC_RESTAPI_ACTION_LINKS_H |  | ||||||
|   | |||||||
| @@ -2,13 +2,13 @@ | |||||||
| // Created by stephane bourque on 2021-07-10.
 | // Created by stephane bourque on 2021-07-10.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_AssetServer.h" | #include "RESTAPI_asset_server.h" | ||||||
| #include "Poco/File.h" | #include "Poco/File.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/ow_constants.h" | ||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_AssetServer::DoGet() { |     void RESTAPI_asset_server::DoGet() { | ||||||
|         Poco::File  AssetFile; |         Poco::File  AssetFile; | ||||||
| 
 | 
 | ||||||
|         if(Request->getURI().find("/favicon.ico") != std::string::npos) { |         if(Request->getURI().find("/favicon.ico") != std::string::npos) { | ||||||
| @@ -2,15 +2,14 @@ | |||||||
| // Created by stephane bourque on 2021-07-10.
 | // Created by stephane bourque on 2021-07-10.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #ifndef UCENTRALSEC_RESTAPI_ASSETSERVER_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_ASSETSERVER_H |  | ||||||
| 
 | 
 | ||||||
| #include "../framework/MicroService.h" | #include "../framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_AssetServer : public RESTAPIHandler { |     class RESTAPI_asset_server : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_POST, |                                          {Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| @@ -19,8 +18,9 @@ namespace OpenWifi { | |||||||
|                                           Poco::Net::HTTPRequest::HTTP_DELETE, |                                           Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|  |                                           TransactionId, | ||||||
|                                           Internal, false) {} |                                           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"}; }; |                                                                                          "/favicon.ico"}; }; | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
|         void DoPost() final {}; |         void DoPost() final {}; | ||||||
| @@ -32,5 +32,3 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #endif //UCENTRALSEC_RESTAPI_ASSETSERVER_H
 |  | ||||||
| @@ -5,10 +5,9 @@ | |||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_avatarHandler.h" | #include "RESTAPI_avatar_handler.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "Poco/Net/HTMLForm.h" | #include "Poco/Net/HTMLForm.h" | ||||||
| #include "framework/RESTAPI_protocol.h" |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| @@ -22,33 +21,27 @@ namespace OpenWifi { | |||||||
|             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); |             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); | ||||||
|         } |         } | ||||||
|         Poco::CountingInputStream InputStream(Stream); |         Poco::CountingInputStream InputStream(Stream); | ||||||
|         std::ofstream OutputStream(TempFile_.path(), std::ofstream::out); |         Poco::StreamCopier::copyStream(InputStream, OutputStream_); | ||||||
|         Poco::StreamCopier::copyStream(InputStream, OutputStream); |         Length_ = OutputStream_.str().size(); | ||||||
|         Length_ = InputStream.chars(); |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatarHandler::DoPost() { |     void RESTAPI_avatar_handler::DoPost() { | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |         std::string Id = UserInfo_.userinfo.id; | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
| 
 | 
 | ||||||
|         if (Id.empty() || !StorageService()->GetUserById(Id, UInfo)) { |         std::stringstream SS; | ||||||
|             return NotFound(); |         AvatarPartHandler partHandler(Id, Logger_, SS); | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         //  if there is an avatar, just remove it...
 |  | ||||||
|         StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); |  | ||||||
| 
 |  | ||||||
|         Poco::TemporaryFile TmpFile; |  | ||||||
|         AvatarPartHandler partHandler(Id, Logger_, TmpFile); |  | ||||||
| 
 |  | ||||||
|         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); |         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); | ||||||
|         Poco::JSON::Object Answer; |         Poco::JSON::Object Answer; | ||||||
|  | 
 | ||||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { |         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); |             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()->SetAvatar(UserInfo_.userinfo.email, |             StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, | ||||||
|                                  Id, TmpFile, partHandler.ContentType(), partHandler.Name()); |                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); | ||||||
|  |             StorageService()->UserDB().SetAvatar(Id,"1"); | ||||||
|  |             Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email)); | ||||||
|         } else { |         } else { | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); |             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||||
| @@ -57,27 +50,33 @@ namespace OpenWifi { | |||||||
|         ReturnObject(Answer); |         ReturnObject(Answer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatarHandler::DoGet() { |     void RESTAPI_avatar_handler::DoGet() { | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|         if (Id.empty()) { |         if (Id.empty()) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|         Poco::TemporaryFile TempAvatar; | 
 | ||||||
|         std::string Type, Name; |         std::string Type, Name, AvatarContent; | ||||||
|         if (!StorageService()->GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) { |         if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|         SendFile(TempAvatar, Type, Name); |         Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size())); | ||||||
|  |         return SendFileContent(AvatarContent, Type, Name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatarHandler::DoDelete() { |     void RESTAPI_avatar_handler::DoDelete() { | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|         if (Id.empty()) { | 
 | ||||||
|             return NotFound(); |         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||||
|         } |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|         if (!StorageService()->DeleteAvatar(UserInfo_.userinfo.email, Id)) { |         } | ||||||
|  | 
 | ||||||
|  |         if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email)); | ||||||
|  |         StorageService()->UserDB().SetAvatar(Id,""); | ||||||
|         OK(); |         OK(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,10 +1,7 @@ | |||||||
| //
 | //
 | ||||||
| // Created by stephane bourque on 2021-07-15.
 | // Created by stephane bourque on 2021-07-15.
 | ||||||
| //
 | //
 | ||||||
| 
 | #pragma once | ||||||
| #ifndef UCENTRALSEC_RESTAPI_AVATARHANDLER_H |  | ||||||
| #define UCENTRALSEC_RESTAPI_AVATARHANDLER_H |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| @@ -12,28 +9,30 @@ namespace OpenWifi { | |||||||
| 
 | 
 | ||||||
|     class AvatarPartHandler : public Poco::Net::PartHandler { |     class AvatarPartHandler : public Poco::Net::PartHandler { | ||||||
|     public: |     public: | ||||||
|         AvatarPartHandler(std::string Id, Poco::Logger &Logger, Poco::TemporaryFile &TmpFile) : |         AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) : | ||||||
|                 Id_(std::move(Id)), |                 Id_(std::move(Id)), | ||||||
|                 Logger_(Logger), |                 Logger_(Logger), | ||||||
|                 TempFile_(TmpFile){ |                 OutputStream_(ofs){ | ||||||
|         } |         } | ||||||
|         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); |         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); | ||||||
|         [[nodiscard]] uint64_t Length() const { return Length_; } |         [[nodiscard]] uint64_t Length() const { return Length_; } | ||||||
|         [[nodiscard]] std::string &Name() { return Name_; } |         [[nodiscard]] std::string &Name() { return Name_; } | ||||||
|         [[nodiscard]] std::string &ContentType() { return FileType_; } |         [[nodiscard]] std::string &ContentType() { return FileType_; } | ||||||
|         [[nodiscard]] std::string FileName() const { return TempFile_.path(); } | 
 | ||||||
|     private: |     private: | ||||||
|         uint64_t        Length_ = 0; |         uint64_t        Length_ = 0; | ||||||
|         std::string     FileType_; |         std::string     FileType_; | ||||||
|         std::string     Name_; |         std::string     Name_; | ||||||
|         std::string     Id_; |         std::string     Id_; | ||||||
|         Poco::Logger    &Logger_; |         Poco::Logger    &Logger_; | ||||||
|         Poco::TemporaryFile &TempFile_; |         std::stringstream &OutputStream_; | ||||||
|  | 
 | ||||||
|  |         inline Poco::Logger & Logger() { return Logger_; }; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class RESTAPI_avatarHandler : public RESTAPIHandler { |     class RESTAPI_avatar_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string>{ |                                  std::vector<std::string>{ | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_GET, |                                          Poco::Net::HTTPRequest::HTTP_GET, | ||||||
| @@ -41,8 +40,9 @@ namespace OpenWifi { | |||||||
|                                          Poco::Net::HTTPRequest::HTTP_DELETE, |                                          Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                          Server, |                                          Server, | ||||||
|  |                                          TransactionId, | ||||||
|                                          Internal) {} |                                          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 DoGet() final; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
| @@ -51,4 +51,3 @@ namespace OpenWifi { | |||||||
| 
 | 
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| #endif //UCENTRALSEC_RESTAPI_AVATARHANDLER_H
 |  | ||||||
							
								
								
									
										17
									
								
								src/RESTAPI/RESTAPI_db_helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/RESTAPI/RESTAPI_db_helpers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-01. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/orm.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     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 "Poco/JSON/Parser.h" | ||||||
|  |  | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/RESTAPI_errors.h" | #include "framework/ow_constants.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_email_handler::DoPost() { |     void RESTAPI_email_handler::DoPost() { | ||||||
|         auto Obj = ParseStream(); |         const auto & Obj = ParsedBody_; | ||||||
|         if (Obj->has("subject") && |         if (Obj->has("subject") && | ||||||
|             Obj->has("from") && |             Obj->has("from") && | ||||||
|             Obj->has("text") && |             Obj->has("text") && | ||||||
|   | |||||||
| @@ -2,27 +2,24 @@ | |||||||
| // Created by stephane bourque on 2021-09-02. | // Created by stephane bourque on 2021-09-02. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef OWSEC_RESTAPI_EMAIL_HANDLER_H | #pragma once | ||||||
| #define OWSEC_RESTAPI_EMAIL_HANDLER_H |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_email_handler : public RESTAPIHandler { |     class RESTAPI_email_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|         : RESTAPIHandler(bindings, L, |         : RESTAPIHandler(bindings, L, | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, |                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                   Server, |                                                   Server, | ||||||
|  |                                                   TransactionId, | ||||||
|                                                   Internal) {} |                                                   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 DoGet() final {}; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
|         void DoDelete() final {}; |         void DoDelete() final {}; | ||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OWSEC_RESTAPI_EMAIL_HANDLER_H |  | ||||||
|   | |||||||
| @@ -1,164 +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. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "Poco/JSON/Parser.h" |  | ||||||
|  |  | ||||||
| #include "Daemon.h" |  | ||||||
| #include "AuthService.h" |  | ||||||
| #include "RESTAPI_oauth2Handler.h" |  | ||||||
| #include "MFAServer.h" |  | ||||||
| #include "framework/RESTAPI_protocol.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     static void FilterCredentials(SecurityObjects::UserInfo & U) { |  | ||||||
|         U.currentPassword.clear(); |  | ||||||
|         U.lastPasswords.clear(); |  | ||||||
|         U.oauthType.clear(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	void RESTAPI_oauth2Handler::DoGet() { |  | ||||||
| 	    bool Expired = false; |  | ||||||
|         if (!IsAuthorized(Expired)) { |  | ||||||
|             if(Expired) |  | ||||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); |  | ||||||
|         } |  | ||||||
|         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)); |  | ||||||
|             Poco::JSON::Object Me; |  | ||||||
|             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; |  | ||||||
|             FilterCredentials(ReturnedUser); |  | ||||||
|             ReturnedUser.to_json(Me); |  | ||||||
|             return ReturnObject(Me); |  | ||||||
|         } |  | ||||||
|         BadRequest(RESTAPI::Errors::UnrecognizedRequest); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     void RESTAPI_oauth2Handler::DoDelete() { |  | ||||||
| 	    bool Expired = false; |  | ||||||
| 	    if (!IsAuthorized(Expired)) { |  | ||||||
| 	        if(Expired) |  | ||||||
| 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); |  | ||||||
| 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); |  | ||||||
| 	    } |  | ||||||
|  |  | ||||||
|         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_oauth2Handler::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); |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(userId); |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) { |  | ||||||
|             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); |  | ||||||
|             Poco::JSON::Object  Answer; |  | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression()); |  | ||||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, Daemon()->GetAccessPolicy()); |  | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, Daemon()->GetPasswordPolicy()); |  | ||||||
|             return ReturnObject(Answer); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { |  | ||||||
|             SecurityObjects::UserInfo UInfo1; |  | ||||||
|             auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1); |  | ||||||
|             if(UserExists) { |  | ||||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", 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.expires = NewLink.created + (24*60*60); |  | ||||||
|                 StorageService()->CreateAction(NewLink); |  | ||||||
|  |  | ||||||
|                 Poco::JSON::Object ReturnObj; |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 UInfo.webtoken.userMustChangePassword = true; |  | ||||||
|                 UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                 return ReturnObject(ReturnObj); |  | ||||||
|             } else { |  | ||||||
|                 Poco::JSON::Object ReturnObj; |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 UInfo.webtoken.userMustChangePassword = true; |  | ||||||
|                 UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                 return ReturnObject(ReturnObj); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { |  | ||||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", 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); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { |  | ||||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); |  | ||||||
|             if(Obj->has("uuid")) { |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) { |  | ||||||
|                     Poco::JSON::Object ReturnObj; |  | ||||||
|                     UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                     return ReturnObject(ReturnObj); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|         bool Expired=false; |  | ||||||
|         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired); |  | ||||||
|         if (Code==SUCCESS) { |  | ||||||
|             Poco::JSON::Object ReturnObj; |  | ||||||
|             if(AuthService()->RequiresMFA(UInfo)) { |  | ||||||
|                 if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { |  | ||||||
|                     return ReturnObject(ReturnObj); |  | ||||||
|                 } |  | ||||||
|                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); |  | ||||||
|             } |  | ||||||
|             UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|             return ReturnObject(ReturnObj); |  | ||||||
|         } else { |  | ||||||
|  |  | ||||||
|             switch(Code) { |  | ||||||
|                 case INVALID_CREDENTIALS: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); |  | ||||||
|                 case PASSWORD_INVALID: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); |  | ||||||
|                 case PASSWORD_ALREADY_USED: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); |  | ||||||
|                 case USERNAME_PENDING_VERIFICATION: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); |  | ||||||
|                 case PASSWORD_CHANGE_REQUIRED: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); |  | ||||||
|                 default: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; |  | ||||||
|             } |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										178
									
								
								src/RESTAPI/RESTAPI_oauth2_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/RESTAPI/RESTAPI_oauth2_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | |||||||
|  | // | ||||||
|  | //	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 "AuthService.h" | ||||||
|  | #include "RESTAPI_oauth2_handler.h" | ||||||
|  | #include "MFAServer.h" | ||||||
|  | #include "framework/ow_constants.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "RESTAPI_db_helpers.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_oauth2_handler::DoGet() { | ||||||
|  |         bool Expired = false, Contacted = false; | ||||||
|  |         if (!IsAuthorized(Expired, Contacted)) { | ||||||
|  |             if (Expired) | ||||||
|  |                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||||
|  |         } | ||||||
|  |         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); | ||||||
|  |             ReturnedUser.to_json(Me); | ||||||
|  |             return ReturnObject(Me); | ||||||
|  |         } | ||||||
|  |         BadRequest(RESTAPI::Errors::UnrecognizedRequest); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_oauth2_handler::DoDelete() { | ||||||
|  |         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); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         AuthService()->Logout(Token); | ||||||
|  |         return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	void RESTAPI_oauth2_handler::DoPost() { | ||||||
|  |  | ||||||
|  |         const auto & Obj = ParsedBody_; | ||||||
|  |         if(Obj == nullptr) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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(!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()); | ||||||
|  |             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy()); | ||||||
|  |             return ReturnObject(Answer); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||||
|  |             SecurityObjects::UserInfo UInfo1; | ||||||
|  |             auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1); | ||||||
|  |             if(UserExists) { | ||||||
|  |                 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 = OpenWifi::Now(); | ||||||
|  |                 NewLink.expires = NewLink.created + (24*60*60); | ||||||
|  |                 NewLink.userAction = true; | ||||||
|  |                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||||
|  |  | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } else { | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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::BAD_MFA_TRANSACTION); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||||
|  |             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)) { | ||||||
|  |                     Poco::JSON::Object ReturnObj; | ||||||
|  |                     UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                     return ReturnObject(ReturnObj); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |         bool Expired=false; | ||||||
|  |         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired); | ||||||
|  |         if (Code==SUCCESS) { | ||||||
|  |             Poco::JSON::Object ReturnObj; | ||||||
|  |             if(AuthService()->RequiresMFA(UInfo)) { | ||||||
|  |                 if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) { | ||||||
|  |                     return ReturnObject(ReturnObj); | ||||||
|  |                 } | ||||||
|  |                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); | ||||||
|  |             } | ||||||
|  |             UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |             return ReturnObject(ReturnObj); | ||||||
|  |         } else { | ||||||
|  |  | ||||||
|  |             switch(Code) { | ||||||
|  |                 case INVALID_CREDENTIALS: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||||
|  |                 case PASSWORD_INVALID: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||||
|  |                 case PASSWORD_ALREADY_USED: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||||
|  |                 case USERNAME_PENDING_VERIFICATION: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||||
|  |                 case PASSWORD_CHANGE_REQUIRED: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||||
|  |                 default: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -6,27 +6,27 @@ | |||||||
| //	Arilia Wireless Inc.
 | //	Arilia Wireless Inc.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #ifndef UCENTRAL_RESTAPI_OAUTH2HANDLER_H | #pragma once | ||||||
| #define UCENTRAL_RESTAPI_OAUTH2HANDLER_H |  | ||||||
| 
 |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| 	class RESTAPI_oauth2Handler : public RESTAPIHandler { | 	class RESTAPI_oauth2_handler : public RESTAPIHandler { | ||||||
| 	  public: | 	  public: | ||||||
| 	    RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | 	    RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
| 			: RESTAPIHandler(bindings, L, | 			: RESTAPIHandler(bindings, L, | ||||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                                       Poco::Net::HTTPRequest::HTTP_GET, |                                                       Poco::Net::HTTPRequest::HTTP_GET, | ||||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
| 													  Server, | 													  Server, | ||||||
|  |                                                       TransactionId, | ||||||
| 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | 													  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 DoGet() final; | ||||||
| 		void DoPost() final; | 		void DoPost() final; | ||||||
| 		void DoDelete() final; | 		void DoDelete() final; | ||||||
| 		void DoPut() final {}; | 		void DoPut() final {}; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| #endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
 | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										36
									
								
								src/RESTAPI/RESTAPI_preferences.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/RESTAPI/RESTAPI_preferences.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-16. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_preferences.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_preferences::DoGet() { | ||||||
|  |         SecurityObjects::Preferences    P; | ||||||
|  |         Poco::JSON::Object  Answer; | ||||||
|  |         StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P); | ||||||
|  |         P.to_json(Answer); | ||||||
|  |         ReturnObject(Answer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_preferences::DoPut() { | ||||||
|  |  | ||||||
|  |         SecurityObjects::Preferences    P; | ||||||
|  |  | ||||||
|  |         const auto & RawObject = ParsedBody_; | ||||||
|  |         if(!P.from_json(RawObject)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         P.id = UserInfo_.userinfo.id; | ||||||
|  |         P.modified = OpenWifi::Now(); | ||||||
|  |         StorageService()->PreferencesDB().SetPreferences(P); | ||||||
|  |  | ||||||
|  |         Poco::JSON::Object  Answer; | ||||||
|  |         P.to_json(Answer); | ||||||
|  |         ReturnObject(Answer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/RESTAPI/RESTAPI_preferences.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/RESTAPI/RESTAPI_preferences.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-16. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_preferences : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_preferences(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_GET, | ||||||
|  |             Poco::Net::HTTPRequest::HTTP_PUT, | ||||||
|  |             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |             Server, | ||||||
|  |             TransactionId, | ||||||
|  |             Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPut() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								src/RESTAPI/RESTAPI_routers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/RESTAPI/RESTAPI_routers.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-10-23. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | #include "RESTAPI/RESTAPI_oauth2_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_user_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_users_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_action_links.h" | ||||||
|  | #include "RESTAPI/RESTAPI_system_endpoints_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_asset_server.h" | ||||||
|  | #include "RESTAPI/RESTAPI_avatar_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_subavatar_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_email_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_sms_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_validate_token_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_preferences.h" | ||||||
|  | #include "RESTAPI/RESTAPI_subpreferences.h" | ||||||
|  | #include "RESTAPI/RESTAPI_suboauth2_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_subuser_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_subusers_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_validate_sub_token_handler.h" | ||||||
|  | #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 std::string &Path, RESTAPIHandler::BindingMap &Bindings, | ||||||
|  |                                                             Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { | ||||||
|  |         return RESTAPI_Router< | ||||||
|  |             RESTAPI_oauth2_handler, | ||||||
|  |             RESTAPI_user_handler, | ||||||
|  |             RESTAPI_users_handler, | ||||||
|  |             RESTAPI_system_command, | ||||||
|  |             RESTAPI_asset_server, | ||||||
|  |             RESTAPI_system_endpoints_handler, | ||||||
|  |             RESTAPI_action_links, | ||||||
|  |             RESTAPI_avatar_handler, | ||||||
|  |             RESTAPI_subavatar_handler, | ||||||
|  |             RESTAPI_email_handler, | ||||||
|  |             RESTAPI_sms_handler, | ||||||
|  |             RESTAPI_preferences, | ||||||
|  |             RESTAPI_subpreferences, | ||||||
|  |             RESTAPI_suboauth2_handler, | ||||||
|  |             RESTAPI_subuser_handler, | ||||||
|  |             RESTAPI_subusers_handler, | ||||||
|  |             RESTAPI_submfa_handler, | ||||||
|  |             RESTAPI_totp_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 std::string &Path, RESTAPIHandler::BindingMap &Bindings, | ||||||
|  |                                                             Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { | ||||||
|  |  | ||||||
|  |         return RESTAPI_Router_I< | ||||||
|  |             RESTAPI_oauth2_handler, | ||||||
|  |             RESTAPI_user_handler, | ||||||
|  |             RESTAPI_users_handler, | ||||||
|  |             RESTAPI_system_command, | ||||||
|  |             RESTAPI_asset_server, | ||||||
|  |             RESTAPI_system_endpoints_handler, | ||||||
|  |             RESTAPI_action_links, | ||||||
|  |             RESTAPI_avatar_handler, | ||||||
|  |             RESTAPI_subavatar_handler, | ||||||
|  |             RESTAPI_email_handler, | ||||||
|  |             RESTAPI_sms_handler, | ||||||
|  |             RESTAPI_preferences, | ||||||
|  |             RESTAPI_subpreferences, | ||||||
|  |             RESTAPI_suboauth2_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 "RESTAPI_sms_handler.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
| #include "framework/RESTAPI_errors.h" | #include "framework/ow_constants.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     void OpenWifi::RESTAPI_sms_handler::DoPost() { |     void OpenWifi::RESTAPI_sms_handler::DoPost() { | ||||||
|         auto Obj = ParseStream(); |         const auto &Obj = ParsedBody_; | ||||||
|  |  | ||||||
|  |         if(!SMSSender()->Enabled()) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         std::string Arg; |         std::string Arg; | ||||||
|         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { |         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { | ||||||
| @@ -18,7 +22,7 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) { |             if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) { | ||||||
|                 return OK(); |                 return OK(); | ||||||
|             } |             } | ||||||
|             return BadRequest("SMS could not be sent to validate device, try later or change the phone number."); |             return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::string Code; |         std::string Code; | ||||||
| @@ -30,7 +34,13 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) { |             if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) { | ||||||
|                 return OK(); |                 return OK(); | ||||||
|             } |             } | ||||||
|             return BadRequest("Code and number could not be validated"); |             return BadRequest(RESTAPI::Errors::SMSCouldNotValidate); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && | ||||||
|  |             UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER && | ||||||
|  |             UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (Obj->has("to") && |         if (Obj->has("to") && | ||||||
| @@ -41,7 +51,7 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->Send(PhoneNumber, Text)) |             if(SMSSender()->Send(PhoneNumber, Text)) | ||||||
|                 return OK(); |                 return OK(); | ||||||
|  |  | ||||||
|             return InternalError("SMS Message could not be sent."); |             return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry); | ||||||
|         } |         } | ||||||
|         BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); |         BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,27 +2,24 @@ | |||||||
| // Created by stephane bourque on 2021-10-09. | // Created by stephane bourque on 2021-10-09. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef OWSEC_RESTAPI_SMS_HANDLER_H | #pragma once | ||||||
| #define OWSEC_RESTAPI_SMS_HANDLER_H |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_sms_handler : public RESTAPIHandler { |     class RESTAPI_sms_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|         : RESTAPIHandler(bindings, L, |         : RESTAPIHandler(bindings, L, | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, |                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                   Server, |                                                   Server, | ||||||
|  |                                                   TransactionId, | ||||||
|                                                   Internal) {} |                                                   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 DoGet() final {}; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
|         void DoDelete() final {}; |         void DoDelete() final {}; | ||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OWSEC_RESTAPI_SMS_HANDLER_H |  | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								src/RESTAPI/RESTAPI_subavatar_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/RESTAPI/RESTAPI_subavatar_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-07-15. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include <fstream> | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | #include "RESTAPI_subavatar_handler.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "Poco/Net/HTMLForm.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) { | ||||||
|  |         FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED); | ||||||
|  |         if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) { | ||||||
|  |             std::string Disposition; | ||||||
|  |             Poco::Net::NameValueCollection Parameters; | ||||||
|  |             Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters); | ||||||
|  |             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); | ||||||
|  |         } | ||||||
|  |         Poco::CountingInputStream InputStream(Stream); | ||||||
|  |         Poco::StreamCopier::copyStream(InputStream, OutputStream_); | ||||||
|  |         Length_ = OutputStream_.str().size(); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     void RESTAPI_subavatar_handler::DoPost() { | ||||||
|  |         std::string Id = UserInfo_.userinfo.id; | ||||||
|  |         SecurityObjects::UserInfo UInfo; | ||||||
|  |  | ||||||
|  |         std::stringstream SS; | ||||||
|  |         SubAvatarPartHandler partHandler(Id, Logger_, SS); | ||||||
|  |         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); | ||||||
|  |         Poco::JSON::Object Answer; | ||||||
|  |  | ||||||
|  |         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(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); | ||||||
|  |             Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete."); | ||||||
|  |         } | ||||||
|  |         ReturnObject(Answer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subavatar_handler::DoGet() { | ||||||
|  |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|  |         if (Id.empty()) { | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         std::string Type, Name, AvatarContent; | ||||||
|  |         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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subavatar_handler::DoDelete() { | ||||||
|  |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|  |  | ||||||
|  |         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||||
|  |             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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								src/RESTAPI/RESTAPI_subavatar_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/RESTAPI/RESTAPI_subavatar_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-07-15. | ||||||
|  | // | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     class SubAvatarPartHandler : public Poco::Net::PartHandler { | ||||||
|  |     public: | ||||||
|  |         SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) : | ||||||
|  |                 Id_(std::move(Id)), | ||||||
|  |                 Logger_(Logger), | ||||||
|  |                 OutputStream_(ofs){ | ||||||
|  |         } | ||||||
|  |         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); | ||||||
|  |         [[nodiscard]] uint64_t Length() const { return Length_; } | ||||||
|  |         [[nodiscard]] std::string &Name() { return Name_; } | ||||||
|  |         [[nodiscard]] std::string &ContentType() { return FileType_; } | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         uint64_t        Length_ = 0; | ||||||
|  |         std::string     FileType_; | ||||||
|  |         std::string     Name_; | ||||||
|  |         std::string     Id_; | ||||||
|  |         Poco::Logger    &Logger_; | ||||||
|  |         std::stringstream &OutputStream_; | ||||||
|  |  | ||||||
|  |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     class RESTAPI_subavatar_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_subavatar_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_GET, | ||||||
|  |                                          Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|  |                                          Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|  |                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                                          Server, | ||||||
|  |                                          TransactionId, | ||||||
|  |                                          Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; }; | ||||||
|  |  | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final; | ||||||
|  |         void DoDelete() final; | ||||||
|  |         void DoPut() final {}; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										137
									
								
								src/RESTAPI/RESTAPI_submfa_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/RESTAPI/RESTAPI_submfa_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-01. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_submfa_handler.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "SMSSender.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_submfa_handler::DoGet() { | ||||||
|  |         SecurityObjects::UserInfo   User; | ||||||
|  |  | ||||||
|  |         if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) { | ||||||
|  |             Poco::JSON::Object              Answer; | ||||||
|  |             SecurityObjects::SubMfaConfig   MFC; | ||||||
|  |  | ||||||
|  |             MFC.id = User.id; | ||||||
|  |             if(User.userTypeProprietaryInfo.mfa.enabled) { | ||||||
|  |                 if(User.userTypeProprietaryInfo.mfa.method == "sms") { | ||||||
|  |                     MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number; | ||||||
|  |                     MFC.type = "sms"; | ||||||
|  |                 } else if(User.userTypeProprietaryInfo.mfa.method == "email") { | ||||||
|  |                     MFC.email = User.email; | ||||||
|  |                     MFC.type = "email"; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 MFC.type = "disabled"; | ||||||
|  |             } | ||||||
|  |             MFC.to_json(Answer); | ||||||
|  |             return ReturnObject(Answer); | ||||||
|  |         } | ||||||
|  |         NotFound(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_submfa_handler::DoPut() { | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             const auto & Body = ParsedBody_; | ||||||
|  |  | ||||||
|  |             SecurityObjects::SubMfaConfig MFC; | ||||||
|  |  | ||||||
|  |             if (!MFC.from_json(Body)) { | ||||||
|  |                 return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (MFC.type == "disabled") { | ||||||
|  |                 SecurityObjects::UserInfo User; | ||||||
|  |                 StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); | ||||||
|  |                 User.userTypeProprietaryInfo.mfa.enabled = false; | ||||||
|  |                 StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); | ||||||
|  |  | ||||||
|  |                 Poco::JSON::Object Answer; | ||||||
|  |                 MFC.to_json(Answer); | ||||||
|  |                 return ReturnObject(Answer); | ||||||
|  |             } else if (MFC.type == "email") { | ||||||
|  |                 SecurityObjects::UserInfo User; | ||||||
|  |  | ||||||
|  |                 StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); | ||||||
|  |                 User.userTypeProprietaryInfo.mfa.enabled = true; | ||||||
|  |                 User.userTypeProprietaryInfo.mfa.method = "email"; | ||||||
|  |                 StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); | ||||||
|  |  | ||||||
|  |                 MFC.sms = MFC.sms; | ||||||
|  |                 MFC.type = "email"; | ||||||
|  |                 MFC.email = UserInfo_.userinfo.email; | ||||||
|  |                 MFC.id = MicroService::instance().CreateUUID(); | ||||||
|  |  | ||||||
|  |                 Poco::JSON::Object Answer; | ||||||
|  |                 MFC.to_json(Answer); | ||||||
|  |                 return ReturnObject(Answer); | ||||||
|  |  | ||||||
|  |             } else if (MFC.type == "sms") { | ||||||
|  |                 if (GetBoolParameter("startValidation", false)) { | ||||||
|  |                     if (MFC.sms.empty()) { | ||||||
|  |                         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(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(RESTAPI::Errors::SMSMissingChallenge); | ||||||
|  |                     } | ||||||
|  |                     if (MFC.sms.empty()) { | ||||||
|  |                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); | ||||||
|  |                     } | ||||||
|  |                     if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) { | ||||||
|  |                         SecurityObjects::UserInfo User; | ||||||
|  |  | ||||||
|  |                         StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); | ||||||
|  |                         User.userTypeProprietaryInfo.mfa.enabled = true; | ||||||
|  |                         User.userTypeProprietaryInfo.mfa.method = "sms"; | ||||||
|  |                         SecurityObjects::MobilePhoneNumber PhoneNumber; | ||||||
|  |                         PhoneNumber.number = MFC.sms; | ||||||
|  |                         PhoneNumber.primary = true; | ||||||
|  |                         PhoneNumber.verified = true; | ||||||
|  |                         User.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                         User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber); | ||||||
|  |  | ||||||
|  |                         StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); | ||||||
|  |  | ||||||
|  |                         MFC.sms = MFC.sms; | ||||||
|  |                         MFC.type = "sms"; | ||||||
|  |                         MFC.email = UserInfo_.userinfo.email; | ||||||
|  |                         MFC.id = MicroService::instance().CreateUUID(); | ||||||
|  |  | ||||||
|  |                         Poco::JSON::Object Answer; | ||||||
|  |                         MFC.to_json(Answer); | ||||||
|  |  | ||||||
|  |                         return ReturnObject(Answer); | ||||||
|  |  | ||||||
|  |                     } else { | ||||||
|  |                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/RESTAPI/RESTAPI_submfa_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/RESTAPI/RESTAPI_submfa_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-01. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_submfa_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_submfa_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_PUT, | ||||||
|  |                                                   Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|  |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                                                   Server, | ||||||
|  |                                                   TransactionId, | ||||||
|  |                                                   Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10}, | ||||||
|  |                                                   true) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |         void DoPut() final ; | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										165
									
								
								src/RESTAPI/RESTAPI_suboauth2_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/RESTAPI/RESTAPI_suboauth2_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_suboauth2_handler.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  | #include "MFAServer.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "RESTAPI/RESTAPI_db_helpers.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_suboauth2_handler::DoGet() { | ||||||
|  |         bool Expired = false, Contacted = false; | ||||||
|  |         if (!IsAuthorized(Expired, Contacted, true)) { | ||||||
|  |             if(Expired) | ||||||
|  |                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||||
|  |         } | ||||||
|  |         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||||
|  |         if(GetMe) { | ||||||
|  |             Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(), | ||||||
|  |                                              UserInfo_.userinfo.email)); | ||||||
|  |             Poco::JSON::Object Me; | ||||||
|  |             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; | ||||||
|  |             Sanitize(UserInfo_, ReturnedUser); | ||||||
|  |             ReturnedUser.to_json(Me); | ||||||
|  |             return ReturnObject(Me); | ||||||
|  |         } | ||||||
|  |         BadRequest(RESTAPI::Errors::UnrecognizedRequest); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_suboauth2_handler::DoDelete() { | ||||||
|  |         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); | ||||||
|  |         } | ||||||
|  |         AuthService()->SubLogout(Token); | ||||||
|  |         return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_suboauth2_handler::DoPost() { | ||||||
|  |         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(!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()); | ||||||
|  |             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy()); | ||||||
|  |             return ReturnObject(Answer); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||||
|  |             SecurityObjects::UserInfo UInfo1; | ||||||
|  |             auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1); | ||||||
|  |             if(UserExists) { | ||||||
|  |                 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 = OpenWifi::Now(); | ||||||
|  |                 NewLink.expires = NewLink.created + (24*60*60); | ||||||
|  |                 NewLink.userAction = false; | ||||||
|  |                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||||
|  |  | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } else { | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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::BAD_MFA_TRANSACTION); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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)) { | ||||||
|  |                     Poco::JSON::Object ReturnObj; | ||||||
|  |                     UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                     return ReturnObject(ReturnObj); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |         bool Expired=false; | ||||||
|  |         auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired); | ||||||
|  |         if (Code==SUCCESS) { | ||||||
|  |             Poco::JSON::Object ReturnObj; | ||||||
|  |             if(AuthService()->RequiresMFA(UInfo)) { | ||||||
|  |                 if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) { | ||||||
|  |                     return ReturnObject(ReturnObj); | ||||||
|  |                 } | ||||||
|  |                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); | ||||||
|  |             } | ||||||
|  |             UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |             return ReturnObject(ReturnObj); | ||||||
|  |         } else { | ||||||
|  |             switch(Code) { | ||||||
|  |                 case INVALID_CREDENTIALS: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||||
|  |                 case PASSWORD_INVALID: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||||
|  |                 case PASSWORD_ALREADY_USED: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||||
|  |                 case USERNAME_PENDING_VERIFICATION: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||||
|  |                 case PASSWORD_CHANGE_REQUIRED: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||||
|  |                 default: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/RESTAPI/RESTAPI_suboauth2_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/RESTAPI/RESTAPI_suboauth2_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_suboauth2_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_suboauth2_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_DELETE, | ||||||
|  |                                                   Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|  |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                                                   Server, | ||||||
|  |                                                   TransactionId, | ||||||
|  |                                                   Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10}, | ||||||
|  |                                                   false) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final; | ||||||
|  |         void DoDelete() final; | ||||||
|  |         void DoPut() final {}; | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								src/RESTAPI/RESTAPI_subpreferences.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/RESTAPI/RESTAPI_subpreferences.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-16. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_subpreferences.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_subpreferences::DoGet() { | ||||||
|  |         SecurityObjects::Preferences    P; | ||||||
|  |         Poco::JSON::Object  Answer; | ||||||
|  |         StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P); | ||||||
|  |         P.to_json(Answer); | ||||||
|  |         ReturnObject(Answer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subpreferences::DoPut() { | ||||||
|  |  | ||||||
|  |         SecurityObjects::Preferences    P; | ||||||
|  |  | ||||||
|  |         const auto & RawObject = ParsedBody_; | ||||||
|  |         if(!P.from_json(RawObject)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         P.id = UserInfo_.userinfo.id; | ||||||
|  |         P.modified = OpenWifi::Now(); | ||||||
|  |         StorageService()->SubPreferencesDB().SetPreferences(P); | ||||||
|  |  | ||||||
|  |         Poco::JSON::Object  Answer; | ||||||
|  |         P.to_json(Answer); | ||||||
|  |         ReturnObject(Answer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/RESTAPI/RESTAPI_subpreferences.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/RESTAPI/RESTAPI_subpreferences.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-16. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_subpreferences : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_subpreferences(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_GET, | ||||||
|  |             Poco::Net::HTTPRequest::HTTP_PUT, | ||||||
|  |             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |             Server, | ||||||
|  |             TransactionId, | ||||||
|  |             Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPut() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								src/RESTAPI/RESTAPI_subtotp_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/RESTAPI/RESTAPI_subtotp_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_subtotp_handler.h" | ||||||
|  |  | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_subtotp_handler::DoGet() { | ||||||
|  |  | ||||||
|  |         auto Reset = GetBoolParameter("reset",false); | ||||||
|  |         std::string QRCode; | ||||||
|  |  | ||||||
|  |         if(TotpCache()->StartValidation(UserInfo_.userinfo,true,QRCode,Reset)) { | ||||||
|  |             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); | ||||||
|  |         } | ||||||
|  |         return BadRequest(RESTAPI::Errors::InvalidCommand); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subtotp_handler::DoPut() { | ||||||
|  |         auto Value = GetParameter("value",""); | ||||||
|  |         auto nextIndex = GetParameter("index",0); | ||||||
|  |         bool moreCodes=false; | ||||||
|  |  | ||||||
|  |         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(Error); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/RESTAPI/RESTAPI_subtotp_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/RESTAPI/RESTAPI_subtotp_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_subtotp_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_subtotp_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_GET, | ||||||
|  |                                                  Poco::Net::HTTPRequest::HTTP_PUT, | ||||||
|  |                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS | ||||||
|  |                                          }, | ||||||
|  |                                  Server, | ||||||
|  |                                  TransactionId, | ||||||
|  |                                  Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |         void DoPut() final; | ||||||
|  |     private: | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										316
									
								
								src/RESTAPI/RESTAPI_subuser_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								src/RESTAPI/RESTAPI_subuser_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,316 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_subuser_handler.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "framework/ow_constants.h" | ||||||
|  | #include "SMSSender.h" | ||||||
|  | #include "SMTPMailerService.h" | ||||||
|  | #include "ACLProcessor.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  | #include "RESTAPI/RESTAPI_db_helpers.h" | ||||||
|  | #include "MFAServer.h" | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_subuser_handler::DoGet() { | ||||||
|  |         std::string Id = GetBinding("id", ""); | ||||||
|  |         if(Id.empty()) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Poco::toLowerInPlace(Id); | ||||||
|  |         std::string Arg; | ||||||
|  |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |         if(HasParameter("byEmail",Arg) && Arg=="true") { | ||||||
|  |             if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) { | ||||||
|  |                 return NotFound(); | ||||||
|  |             } | ||||||
|  |         } else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) { | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Poco::JSON::Object  UserInfoObject; | ||||||
|  |         Sanitize(UserInfo_, UInfo); | ||||||
|  |         UInfo.to_json(UserInfoObject); | ||||||
|  |         ReturnObject(UserInfoObject); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subuser_handler::DoDelete() { | ||||||
|  |         std::string Id = GetBinding("id", ""); | ||||||
|  |         if(Id.empty()) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfo TargetUser; | ||||||
|  |         if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) { | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         AuthService()->DeleteSubUserFromCache(Id); | ||||||
|  |         StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email); | ||||||
|  |         StorageService()->SubPreferencesDB().DeleteRecord("id", Id); | ||||||
|  |         StorageService()->SubAvatarDB().DeleteRecord("id", Id); | ||||||
|  |         Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email)); | ||||||
|  |         OK(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subuser_handler::DoPost() { | ||||||
|  |         std::string Id = GetBinding("id", ""); | ||||||
|  |         if(Id!="0") { | ||||||
|  |             return BadRequest(RESTAPI::Errors::IdMustBe0); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfo   NewUser; | ||||||
|  |         const auto & RawObject = ParsedBody_; | ||||||
|  |         if(!NewUser.from_json(RawObject)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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); | ||||||
|  |         if(!Utils::ValidEMailAddress(NewUser.email)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(!NewUser.currentPassword.empty()) { | ||||||
|  |             if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) { | ||||||
|  |                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(NewUser.name.empty()) | ||||||
|  |             NewUser.name = NewUser.email; | ||||||
|  |  | ||||||
|  |         //  You cannot enable MFA during user creation | ||||||
|  |         NewUser.userTypeProprietaryInfo.mfa.enabled = false; | ||||||
|  |         NewUser.userTypeProprietaryInfo.mfa.method = ""; | ||||||
|  |         NewUser.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |  | ||||||
|  |         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(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(fmt::format("User '{}' but not retrieved.",NewUser.email)); | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Poco::JSON::Object  UserInfoObject; | ||||||
|  |         Sanitize(UserInfo_, NewUser); | ||||||
|  |         NewUser.to_json(UserInfoObject); | ||||||
|  |         ReturnObject(UserInfoObject); | ||||||
|  |         Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_subuser_handler::DoPut() { | ||||||
|  |         std::string Id = GetBinding("id", ""); | ||||||
|  |         if(Id.empty()) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfo   Existing; | ||||||
|  |         if(!StorageService()->SubDB().GetUserById(Id,Existing)) { | ||||||
|  |             return NotFound(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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; | ||||||
|  |         const auto & RawObject = ParsedBody_; | ||||||
|  |         if(!NewUser.from_json(RawObject)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // some basic validations | ||||||
|  |         if(RawObject->has("userRole") && | ||||||
|  |             (SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN || | ||||||
|  |             SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // The only valid things to change are: changePassword, name, | ||||||
|  |         AssignIfPresent(RawObject,"name", Existing.name); | ||||||
|  |         AssignIfPresent(RawObject,"description", Existing.description); | ||||||
|  |         AssignIfPresent(RawObject,"owner", Existing.owner); | ||||||
|  |         AssignIfPresent(RawObject,"location", Existing.location); | ||||||
|  |         AssignIfPresent(RawObject,"locale", Existing.locale); | ||||||
|  |         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); | ||||||
|  |         AssignIfPresent(RawObject,"suspended", Existing.suspended); | ||||||
|  |         AssignIfPresent(RawObject,"blackListed", Existing.blackListed); | ||||||
|  |  | ||||||
|  |         if(RawObject->has("userRole")) { | ||||||
|  |             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::ACCESS_DENIED); | ||||||
|  |                 } | ||||||
|  |                 if(Id==UserInfo_.userinfo.id) { | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|  |                 } | ||||||
|  |                 Existing.userRole = NewRole; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(RawObject->has("notes")) { | ||||||
|  |             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)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||||
|  |                 Existing.notes.push_back(ii); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(RawObject->has("currentPassword")) { | ||||||
|  |             if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) { | ||||||
|  |                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||||
|  |             } | ||||||
|  |             if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) { | ||||||
|  |                 return BadRequest(RESTAPI::Errors::PasswordRejected); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(GetParameter("email_verification","false")=="true") { | ||||||
|  |             if(AuthService::VerifySubEmail(Existing)) | ||||||
|  |                 Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(RawObject->has("userTypeProprietaryInfo")) { | ||||||
|  |             if(NewUser.userTypeProprietaryInfo.mfa.enabled) { | ||||||
|  |                 if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) { | ||||||
|  |                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||||
|  |                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||||
|  |                     !SMSSender()->Enabled()) { | ||||||
|  |                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 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 (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||||
|  |                     std::string Secret; | ||||||
|  |                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||||
|  |                         Existing.userTypeProprietaryInfo.authenticatorSecret = Secret; | ||||||
|  |                     } else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||||
|  |                         // we allow someone to use their old secret | ||||||
|  |                     } else { | ||||||
|  |                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||||
|  |                     } | ||||||
|  |                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||||
|  |                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                 Existing.userTypeProprietaryInfo.mfa.enabled = false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||||
|  |             SecurityObjects::UserInfo   NewUserInfo; | ||||||
|  |             StorageService()->SubDB().GetUserById(Id,NewUserInfo); | ||||||
|  |             Poco::JSON::Object  ModifiedObject; | ||||||
|  |             Sanitize(UserInfo_, NewUserInfo); | ||||||
|  |             NewUserInfo.to_json(ModifiedObject); | ||||||
|  |             return ReturnObject(ModifiedObject); | ||||||
|  |         } | ||||||
|  |         BadRequest(RESTAPI::Errors::RecordNotUpdated); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								src/RESTAPI/RESTAPI_subuser_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/RESTAPI/RESTAPI_subuser_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_subuser_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_subuser_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_GET, | ||||||
|  |                           Poco::Net::HTTPRequest::HTTP_PUT, | ||||||
|  |                           Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|  |                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                           Server, | ||||||
|  |                           TransactionId, | ||||||
|  |                           Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final; | ||||||
|  |         void DoDelete() final; | ||||||
|  |         void DoPut() final; | ||||||
|  |     private: | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								src/RESTAPI/RESTAPI_subusers_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/RESTAPI/RESTAPI_subusers_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_subusers_handler.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  | #include "RESTAPI/RESTAPI_db_helpers.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_subusers_handler::DoGet() { | ||||||
|  |         bool IdOnly = GetBoolParameter("idOnly"); | ||||||
|  |         auto operatorId = GetParameter("operatorId"); | ||||||
|  |         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_.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); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             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 { | ||||||
|  |             SecurityObjects::UserInfoList   Users; | ||||||
|  |             for(auto &i:SelectedRecords()) { | ||||||
|  |                 SecurityObjects::UserInfo   UInfo; | ||||||
|  |                 if(StorageService()->SubDB().GetUserById(i,UInfo)) { | ||||||
|  |                     Poco::JSON::Object Obj; | ||||||
|  |                     Sanitize(UserInfo_, UInfo); | ||||||
|  |                     Users.users.emplace_back(UInfo); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Poco::JSON::Object Answer; | ||||||
|  |             Users.to_json(Answer); | ||||||
|  |             return ReturnObject(Answer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								src/RESTAPI/RESTAPI_subusers_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/RESTAPI/RESTAPI_subusers_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_subusers_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_subusers_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_GET, | ||||||
|  |                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                           Server, | ||||||
|  |                           TransactionId, | ||||||
|  |                           Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/subusers"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |         void DoPut() final {}; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_systemEndpoints_handler.h" | #include "RESTAPI_system_endpoints_handler.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_systemEndpoints_handler::DoGet() { |     void RESTAPI_system_endpoints_handler::DoGet() { | ||||||
|         auto Services = MicroService::instance().GetServices(); |         auto Services = MicroService::instance().GetServices(); | ||||||
|         SecurityObjects::SystemEndpointList L; |         SecurityObjects::SystemEndpointList L; | ||||||
|         for(const auto &i:Services) { |         for(const auto &i:Services) { | ||||||
| @@ -2,26 +2,24 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #ifndef UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H |  | ||||||
| 
 | 
 | ||||||
| #include "../framework/MicroService.h" | #include "../framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_systemEndpoints_handler : public RESTAPIHandler { |     class RESTAPI_system_endpoints_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_system_endpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, |                                  std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                           Server, |                                                           Server, | ||||||
|  |                                                           TransactionId, | ||||||
|                                                           Internal) {} |                                                           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 DoGet() final; | ||||||
|         void DoPost() final {}; |         void DoPost() final {}; | ||||||
|         void DoDelete() final {}; |         void DoDelete() final {}; | ||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #endif //UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
 |  | ||||||
							
								
								
									
										35
									
								
								src/RESTAPI/RESTAPI_totp_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/RESTAPI/RESTAPI_totp_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_totp_handler.h" | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     void RESTAPI_totp_handler::DoGet() { | ||||||
|  |  | ||||||
|  |         auto Reset = GetBoolParameter("reset",false); | ||||||
|  |         std::string QRCode; | ||||||
|  |         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { | ||||||
|  |             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); | ||||||
|  |         } | ||||||
|  |         return BadRequest(RESTAPI::Errors::InvalidCommand); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_totp_handler::DoPut() { | ||||||
|  |         auto Value = GetParameter("value",""); | ||||||
|  |         auto nextIndex = GetParameter("index",0); | ||||||
|  |         bool moreCodes=false; | ||||||
|  |  | ||||||
|  |         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(Err); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								src/RESTAPI/RESTAPI_totp_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/RESTAPI/RESTAPI_totp_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_totp_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_totp_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_GET, | ||||||
|  |                                               Poco::Net::HTTPRequest::HTTP_PUT, | ||||||
|  |                                               Poco::Net::HTTPRequest::HTTP_OPTIONS | ||||||
|  |                                           }, | ||||||
|  |                                  Server, | ||||||
|  |                                  TransactionId, | ||||||
|  |                                  Internal) {} | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/totp"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |         void DoPut() final; | ||||||
|  |     private: | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | } | ||||||
| @@ -4,19 +4,17 @@ | |||||||
|  |  | ||||||
| #include "RESTAPI_user_handler.h" | #include "RESTAPI_user_handler.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "Poco/JSON/Parser.h" | #include "framework/ow_constants.h" | ||||||
| #include "framework/RESTAPI_errors.h" |  | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
|  | #include "SMTPMailerService.h" | ||||||
| #include "ACLProcessor.h" | #include "ACLProcessor.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  | #include "RESTAPI/RESTAPI_db_helpers.h" | ||||||
|  | #include "MFAServer.h" | ||||||
|  | #include "TotpCache.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static void FilterCredentials(SecurityObjects::UserInfo & U) { |  | ||||||
|         U.currentPassword.clear(); |  | ||||||
|         U.lastPasswords.clear(); |  | ||||||
|         U.oauthType.clear(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_user_handler::DoGet() { |     void RESTAPI_user_handler::DoGet() { | ||||||
|         std::string Id = GetBinding("id", ""); |         std::string Id = GetBinding("id", ""); | ||||||
|         if(Id.empty()) { |         if(Id.empty()) { | ||||||
| @@ -27,15 +25,19 @@ namespace OpenWifi { | |||||||
|         std::string Arg; |         std::string Arg; | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|         if(HasParameter("byEmail",Arg) && Arg=="true") { |         if(HasParameter("byEmail",Arg) && Arg=="true") { | ||||||
|             if(!StorageService()->GetUserByEmail(Id,UInfo)) { |             if(!StorageService()->UserDB().GetUserByEmail(Id,UInfo)) { | ||||||
|                 return NotFound(); |                 return NotFound(); | ||||||
|             } |             } | ||||||
|         } else if(!StorageService()->GetUserById(Id,UInfo)) { |         } else if(!StorageService()->UserDB().GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) { | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         FilterCredentials(UInfo); |         Sanitize(UserInfo_, UInfo); | ||||||
|         UInfo.to_json(UserInfoObject); |         UInfo.to_json(UserInfoObject); | ||||||
|         ReturnObject(UserInfoObject); |         ReturnObject(UserInfoObject); | ||||||
|     } |     } | ||||||
| @@ -47,45 +49,51 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
|         if(!StorageService()->GetUserById(Id,UInfo)) { |         if(!StorageService()->UserDB().GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { |         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { |         if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(AuthService()->DeleteUserFromCache(UInfo.email)) { |         AuthService()->DeleteUserFromCache(Id); | ||||||
|             // nothing to do |         StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||||
|         } |         StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id); | ||||||
|  |         StorageService()->UserTokenDB().RevokeAllTokens(Id); | ||||||
|         StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); |         Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email)); | ||||||
|  |  | ||||||
|         Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); |  | ||||||
|         StorageService()->RevokeAllTokens(UInfo.email); |  | ||||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); |  | ||||||
|         OK(); |         OK(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_user_handler::DoPost() { |     void RESTAPI_user_handler::DoPost() { | ||||||
|  |  | ||||||
|         std::string Id = GetBinding("id", ""); |         std::string Id = GetBinding("id", ""); | ||||||
|         if(Id!="0") { |         if(Id!="0") { | ||||||
|             return BadRequest(RESTAPI::Errors::IdMustBe0); |             return BadRequest(RESTAPI::Errors::IdMustBe0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |         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) { |         if(NewUser.userRole == SecurityObjects::UNKNOWN) { | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if(UserInfo_.userinfo.userRole==SecurityObjects::ROOT) { | ||||||
|  |             NewUser.owner = GetParameter("entity",""); | ||||||
|  |         } else { | ||||||
|  |             NewUser.owner = UserInfo_.userinfo.owner; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { |         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); |             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(NewUser.email); |         Poco::toLowerInPlace(NewUser.email); | ||||||
| @@ -93,6 +101,11 @@ namespace OpenWifi { | |||||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); |             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(!NewUser.currentPassword.empty()) { | ||||||
|             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { |             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); |                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||||
| @@ -102,46 +115,93 @@ namespace OpenWifi { | |||||||
|         if(NewUser.name.empty()) |         if(NewUser.name.empty()) | ||||||
|             NewUser.name = NewUser.email; |             NewUser.name = NewUser.email; | ||||||
|  |  | ||||||
|         if(!StorageService()->CreateUser(NewUser.email,NewUser)) { |         //  You cannot enable MFA during user creation | ||||||
|             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); |         NewUser.userTypeProprietaryInfo.mfa.enabled = false; | ||||||
|  |         NewUser.userTypeProprietaryInfo.mfa.method = ""; | ||||||
|  |         NewUser.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |         NewUser.validated = true; | ||||||
|  |  | ||||||
|  |         if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) { | ||||||
|  |             Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email)); | ||||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); |             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetParameter("email_verification","false")=="true") { |         if(GetBoolParameter("email_verification")) { | ||||||
|             if(AuthService::VerifyEmail(NewUser)) |             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()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser); |             StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->GetUserByEmail(NewUser.email, 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(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         FilterCredentials(NewUser); |         Sanitize(UserInfo_, NewUser); | ||||||
|         NewUser.to_json(UserInfoObject); |         NewUser.to_json(UserInfoObject); | ||||||
|         ReturnObject(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() { |     void RESTAPI_user_handler::DoPut() { | ||||||
|  |  | ||||||
|         std::string Id = GetBinding("id", ""); |         std::string Id = GetBinding("id", ""); | ||||||
|         if(Id.empty()) { |         if(Id.empty()) { | ||||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); |             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   Existing; |         SecurityObjects::UserInfo   Existing; | ||||||
|         if(!StorageService()->GetUserById(Id,Existing)) { |         if(!StorageService()->UserDB().GetUserById(Id,Existing)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { |         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; |         SecurityObjects::UserInfo   NewUser; | ||||||
|         auto RawObject = ParseStream(); |         const auto & RawObject = ParsedBody_; | ||||||
|         if(!NewUser.from_json(RawObject)) { |         if(!NewUser.from_json(RawObject)) { | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|         } |         } | ||||||
| @@ -151,10 +211,15 @@ namespace OpenWifi { | |||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if(RawObject->has("owner")) { | ||||||
|  |             if (UserInfo_.userinfo.userRole == SecurityObjects::ROOT && Existing.owner.empty()) { | ||||||
|  |                 AssignIfPresent(RawObject, "owner", Existing.owner); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // The only valid things to change are: changePassword, name, |         // The only valid things to change are: changePassword, name, | ||||||
|         AssignIfPresent(RawObject,"name", Existing.name); |         AssignIfPresent(RawObject,"name", Existing.name); | ||||||
|         AssignIfPresent(RawObject,"description", Existing.description); |         AssignIfPresent(RawObject,"description", Existing.description); | ||||||
|         AssignIfPresent(RawObject,"owner", Existing.owner); |  | ||||||
|         AssignIfPresent(RawObject,"location", Existing.location); |         AssignIfPresent(RawObject,"location", Existing.location); | ||||||
|         AssignIfPresent(RawObject,"locale", Existing.locale); |         AssignIfPresent(RawObject,"locale", Existing.locale); | ||||||
|         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); |         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); | ||||||
| @@ -165,10 +230,10 @@ namespace OpenWifi { | |||||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); |             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||||
|             if(NewRole!=Existing.userRole) { |             if(NewRole!=Existing.userRole) { | ||||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { |                 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) { |                 if(Id==UserInfo_.userinfo.id) { | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||||
|                 } |                 } | ||||||
|                 Existing.userRole = NewRole; |                 Existing.userRole = NewRole; | ||||||
|             } |             } | ||||||
| @@ -178,7 +243,7 @@ namespace OpenWifi { | |||||||
|             SecurityObjects::NoteInfoVec NIV; |             SecurityObjects::NoteInfoVec NIV; | ||||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); |             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||||
|             for(auto const &i:NIV) { |             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); |                 Existing.notes.push_back(ii); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -191,48 +256,69 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetParameter("email_verification","false")=="true") { |         if(GetBoolParameter("email_verification")) { | ||||||
|             if(AuthService::VerifyEmail(Existing)) |             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")) { |         if(RawObject->has("userTypeProprietaryInfo")) { | ||||||
|             bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; |             if(NewUser.userTypeProprietaryInfo.mfa.enabled) { | ||||||
|  |                 if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) { | ||||||
|             Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; |                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||||
|  |  | ||||||
|             auto PropInfo = RawObject->get("userTypeProprietaryInfo"); |  | ||||||
|             auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|  |  | ||||||
|             if(PInfo->isArray("mobiles")) { |  | ||||||
|                 Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){ |  | ||||||
|                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) { |  | ||||||
|                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) { |  | ||||||
|                 if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) { |  | ||||||
|                     return BadRequest("Unknown MFA method"); |  | ||||||
|                 } |                 } | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) { |                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||||
|                 return BadRequest("Illegal MFA method"); |                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||||
|  |                     !SMSSender()->Enabled()) { | ||||||
|  |                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 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 (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||||
|  |                     std::string Secret; | ||||||
|  |                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||||
|  |                         Existing.userTypeProprietaryInfo.authenticatorSecret = Secret; | ||||||
|  |                     } else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||||
|  |                         // we allow someone to use their old secret | ||||||
|  |                     } else { | ||||||
|  |                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||||
|  |                     } | ||||||
|  |                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||||
|  |                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||||
|  |                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||||
|  |                 Existing.userTypeProprietaryInfo.mfa.enabled = false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { |         Existing.modified = OpenWifi::Now(); | ||||||
|  |         if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||||
|             SecurityObjects::UserInfo   NewUserInfo; |             SecurityObjects::UserInfo   NewUserInfo; | ||||||
|             StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); |             StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||||
|             Poco::JSON::Object  ModifiedObject; |             Poco::JSON::Object  ModifiedObject; | ||||||
|             FilterCredentials(NewUserInfo); |             Sanitize(UserInfo_, NewUserInfo); | ||||||
|             NewUserInfo.to_json(ModifiedObject); |             NewUserInfo.to_json(ModifiedObject); | ||||||
|             return ReturnObject(ModifiedObject); |             return ReturnObject(ModifiedObject); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -2,15 +2,14 @@ | |||||||
| // Created by stephane bourque on 2021-06-21. | // Created by stephane bourque on 2021-06-21. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef UCENTRALSEC_RESTAPI_USER_HANDLER_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_USER_HANDLER_H |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_user_handler : public RESTAPIHandler { |     class RESTAPI_user_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_POST, |                                          {Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| @@ -19,8 +18,9 @@ namespace OpenWifi { | |||||||
|                                           Poco::Net::HTTPRequest::HTTP_DELETE, |                                           Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|  |                                           TransactionId, | ||||||
|                                           Internal) {} |                                           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 DoGet() final; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
|         void DoDelete() final; |         void DoDelete() final; | ||||||
| @@ -29,6 +29,3 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif //UCENTRALSEC_RESTAPI_USER_HANDLER_H |  | ||||||
|   | |||||||
| @@ -4,54 +4,55 @@ | |||||||
|  |  | ||||||
| #include "RESTAPI_users_handler.h" | #include "RESTAPI_users_handler.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "framework/RESTAPI_protocol.h" |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  | #include "RESTAPI/RESTAPI_db_helpers.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_users_handler::DoGet() { |     void RESTAPI_users_handler::DoGet() { | ||||||
|         std::vector<SecurityObjects::UserInfo> Users; |  | ||||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); |         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()) { |         if(QB_.Select.empty()) { | ||||||
|             Poco::JSON::Array ArrayObj; |             SecurityObjects::UserInfoList   Users; | ||||||
|             Poco::JSON::Object Answer; |             if(StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, baseQuery)) { | ||||||
|             if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { |                 for (auto &i : Users.users) { | ||||||
|                 for (auto &i : Users) { |                     Sanitize(UserInfo_, i); | ||||||
|                     Poco::JSON::Object Obj; |                 } | ||||||
|                     if (IdOnly) { |                 if(IdOnly) { | ||||||
|                         ArrayObj.add(i.Id); |                     Poco::JSON::Array   Arr; | ||||||
|                     } else { |                     for(const auto &i:Users.users) | ||||||
|                         i.currentPassword.clear(); |                         Arr.add(i.id); | ||||||
|                         i.lastPasswords.clear(); |                     Poco::JSON::Object  Answer; | ||||||
|                         i.oauthType.clear(); |                     Answer.set("users", Arr); | ||||||
|                         i.to_json(Obj); |                     return ReturnObject(Answer); | ||||||
|                         ArrayObj.add(Obj); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); |  | ||||||
|             } |             } | ||||||
|  |             Poco::JSON::Object  Answer; | ||||||
|  |             Users.to_json(Answer); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|         } else { |         } else { | ||||||
|             Types::StringVec IDs = Utils::Split(QB_.Select); |             SecurityObjects::UserInfoList   Users; | ||||||
|             Poco::JSON::Array ArrayObj; |             for(auto &i:SelectedRecords()) { | ||||||
|             for(auto &i:IDs) { |  | ||||||
|                 SecurityObjects::UserInfo   UInfo; |                 SecurityObjects::UserInfo   UInfo; | ||||||
|                 if(StorageService()->GetUserById(i,UInfo)) { |                 if(StorageService()->UserDB().GetUserById(i,UInfo)) { | ||||||
|                     Poco::JSON::Object Obj; |                     Poco::JSON::Object Obj; | ||||||
|                     if (IdOnly) { |                     Sanitize(UserInfo_, UInfo); | ||||||
|                         ArrayObj.add(UInfo.Id); |                     Users.users.emplace_back(UInfo); | ||||||
|                     } else { |  | ||||||
|                         UInfo.currentPassword.clear(); |  | ||||||
|                         UInfo.lastPasswords.clear(); |  | ||||||
|                         UInfo.oauthType.clear(); |  | ||||||
|                         UInfo.to_json(Obj); |  | ||||||
|                         ArrayObj.add(Obj); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Poco::JSON::Object RetObj; |             Poco::JSON::Object Answer; | ||||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); |             Users.to_json(Answer); | ||||||
|             return ReturnObject(RetObj); |             return ReturnObject(Answer); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -2,22 +2,22 @@ | |||||||
| // Created by stephane bourque on 2021-06-21. | // Created by stephane bourque on 2021-06-21. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef UCENTRALSEC_RESTAPI_USERS_HANDLER_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_USERS_HANDLER_H |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_users_handler : public RESTAPIHandler { |     class RESTAPI_users_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                  {Poco::Net::HTTPRequest::HTTP_GET, |                                  {Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                   Server, |                                   Server, | ||||||
|  |                                   TransactionId, | ||||||
|                                   Internal) {} |                                   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 DoGet() final; | ||||||
|         void DoPost() final {}; |         void DoPost() final {}; | ||||||
|         void DoDelete() final {}; |         void DoDelete() final {}; | ||||||
| @@ -25,5 +25,3 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif //UCENTRALSEC_RESTAPI_USERS_HANDLER_H |  | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_validate_sub_token_handler.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     void RESTAPI_validate_sub_token_handler::DoGet() { | ||||||
|  |         Poco::URI URI(Request->getURI()); | ||||||
|  |         auto Parameters = URI.getQueryParameters(); | ||||||
|  |         for(auto const &i:Parameters) { | ||||||
|  |             if (i.first == "token") { | ||||||
|  |                 //  can we find this token? | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy SecObj; | ||||||
|  |                 bool Expired = false; | ||||||
|  |                 if (AuthService()->IsValidSubToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) { | ||||||
|  |                     Poco::JSON::Object Obj; | ||||||
|  |                     SecObj.to_json(Obj); | ||||||
|  |                     return ReturnObject(Obj); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return NotFound(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								src/RESTAPI/RESTAPI_validate_sub_token_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/RESTAPI/RESTAPI_validate_sub_token_handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     class RESTAPI_validate_sub_token_handler : public RESTAPIHandler { | ||||||
|  |     public: | ||||||
|  |         RESTAPI_validate_sub_token_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_GET, | ||||||
|  |                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|  |                           Server, | ||||||
|  |                           TransactionId, | ||||||
|  |                           Internal) {}; | ||||||
|  |         static auto PathName() { return std::list<std::string>{"/api/v1/validateSubToken"}; }; | ||||||
|  |         void DoGet() final; | ||||||
|  |         void DoPost() final {}; | ||||||
|  |         void DoDelete() final {}; | ||||||
|  |         void DoPut() final {}; | ||||||
|  |     }; | ||||||
|  | } | ||||||
| @@ -2,11 +2,11 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_validateToken_handler.h" | #include "RESTAPI_validate_token_handler.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_validateToken_handler::DoGet() { |     void RESTAPI_validate_token_handler::DoGet() { | ||||||
|         Poco::URI URI(Request->getURI()); |         Poco::URI URI(Request->getURI()); | ||||||
|         auto Parameters = URI.getQueryParameters(); |         auto Parameters = URI.getQueryParameters(); | ||||||
|         for(auto const &i:Parameters) { |         for(auto const &i:Parameters) { | ||||||
| @@ -2,22 +2,22 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #ifndef UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H | #pragma once | ||||||
| #define UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H |  | ||||||
| 
 | 
 | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_validateToken_handler : public RESTAPIHandler { |     class RESTAPI_validate_token_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) |         RESTAPI_validate_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_GET, |                                          {Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|  |                                           TransactionId, | ||||||
|                                           Internal) {}; |                                           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 DoGet() final; | ||||||
|         void DoPost() final {}; |         void DoPost() final {}; | ||||||
|         void DoDelete() final {}; |         void DoDelete() final {}; | ||||||
| @@ -25,4 +25,3 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif //UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
 |  | ||||||
							
								
								
									
										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); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										208
									
								
								src/RESTObjects/RESTAPI_CertObjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								src/RESTObjects/RESTAPI_CertObjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-07. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_CertObjects.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  |  | ||||||
|  | namespace OpenWifi::CertObjects { | ||||||
|  |     void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"entity", entity); | ||||||
|  |         field_to_json(Obj,"creator", creator); | ||||||
|  |         field_to_json(Obj,"type", type); | ||||||
|  |         field_to_json(Obj,"status", status); | ||||||
|  |         field_to_json(Obj,"certificate", certificate); | ||||||
|  |         field_to_json(Obj,"key", key); | ||||||
|  |         field_to_json(Obj,"devid", devid); | ||||||
|  |         field_to_json(Obj,"cas", cas); | ||||||
|  |         field_to_json(Obj,"manufacturer", manufacturer); | ||||||
|  |         field_to_json(Obj,"model", model); | ||||||
|  |         field_to_json(Obj,"redirector", redirector); | ||||||
|  |         field_to_json(Obj,"commonName", commonName); | ||||||
|  |         field_to_json(Obj,"certificateId", certificateId); | ||||||
|  |         field_to_json(Obj,"batch", batch); | ||||||
|  |         field_to_json(Obj,"created", created); | ||||||
|  |         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) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"entity", entity); | ||||||
|  |             field_from_json(Obj,"creator", creator); | ||||||
|  |             field_from_json(Obj,"type", type); | ||||||
|  |             field_from_json(Obj,"status", status); | ||||||
|  |             field_from_json(Obj,"certificate", certificate); | ||||||
|  |             field_from_json(Obj,"key", key); | ||||||
|  |             field_from_json(Obj,"devid", devid); | ||||||
|  |             field_from_json(Obj,"cas", cas); | ||||||
|  |             field_from_json(Obj,"manufacturer", manufacturer); | ||||||
|  |             field_from_json(Obj,"model", model); | ||||||
|  |             field_from_json(Obj,"redirector", redirector); | ||||||
|  |             field_from_json(Obj,"commonName", commonName); | ||||||
|  |             field_from_json(Obj,"certificateId", certificateId); | ||||||
|  |             field_from_json(Obj,"batch", batch); | ||||||
|  |             field_from_json(Obj,"created", created); | ||||||
|  |             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 (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void EntityEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"creator", creator); | ||||||
|  |         field_to_json(Obj,"name", name); | ||||||
|  |         field_to_json(Obj,"description", description); | ||||||
|  |         field_to_json(Obj,"defaultRedirector", defaultRedirector); | ||||||
|  |         field_to_json(Obj,"apiKey", apiKey); | ||||||
|  |         field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); | ||||||
|  |         field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); | ||||||
|  |         field_to_json(Obj,"organization", organization); | ||||||
|  |         field_to_json(Obj,"created", created); | ||||||
|  |         field_to_json(Obj,"modified", modified); | ||||||
|  |         field_to_json(Obj,"suspended", suspended); | ||||||
|  |         field_to_json(Obj,"deleted", deleted); | ||||||
|  |         field_to_json(Obj,"notes", notes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"creator", creator); | ||||||
|  |             field_from_json(Obj,"name", name); | ||||||
|  |             field_from_json(Obj,"description", description); | ||||||
|  |             field_from_json(Obj,"defaultRedirector", defaultRedirector); | ||||||
|  |             field_from_json(Obj,"apiKey", apiKey); | ||||||
|  |             field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); | ||||||
|  |             field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); | ||||||
|  |             field_from_json(Obj,"organization", organization); | ||||||
|  |             field_from_json(Obj,"created", created); | ||||||
|  |             field_from_json(Obj,"modified", modified); | ||||||
|  |             field_from_json(Obj,"suspended", suspended); | ||||||
|  |             field_from_json(Obj,"deleted", deleted); | ||||||
|  |             field_from_json(Obj,"notes", notes); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void BatchEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"entity", entity); | ||||||
|  |         field_to_json(Obj,"creator", creator); | ||||||
|  |         field_to_json(Obj,"name", name); | ||||||
|  |         field_to_json(Obj,"description", description); | ||||||
|  |         field_to_json(Obj,"manufacturer", manufacturer); | ||||||
|  |         field_to_json(Obj,"model", model); | ||||||
|  |         field_to_json(Obj,"redirector", redirector); | ||||||
|  |         field_to_json(Obj,"commonNames", commonNames); | ||||||
|  |         field_to_json(Obj,"jobHistory", jobHistory); | ||||||
|  |         field_to_json(Obj,"notes", notes); | ||||||
|  |         field_to_json(Obj,"submitted", submitted); | ||||||
|  |         field_to_json(Obj,"started", started); | ||||||
|  |         field_to_json(Obj,"completed", completed); | ||||||
|  |         field_to_json(Obj,"modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"entity", entity); | ||||||
|  |             field_from_json(Obj,"creator", creator); | ||||||
|  |             field_from_json(Obj,"name", name); | ||||||
|  |             field_from_json(Obj,"description", description); | ||||||
|  |             field_from_json(Obj,"manufacturer", manufacturer); | ||||||
|  |             field_from_json(Obj,"model", model); | ||||||
|  |             field_from_json(Obj,"redirector", redirector); | ||||||
|  |             field_from_json(Obj,"commonNames", commonNames); | ||||||
|  |             field_from_json(Obj,"jobHistory", jobHistory); | ||||||
|  |             field_from_json(Obj,"notes", notes); | ||||||
|  |             field_from_json(Obj,"submitted", submitted); | ||||||
|  |             field_from_json(Obj,"started", started); | ||||||
|  |             field_from_json(Obj,"completed", completed); | ||||||
|  |             field_from_json(Obj,"modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void JobEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"entity", entity); | ||||||
|  |         field_to_json(Obj,"creator", creator); | ||||||
|  |         field_to_json(Obj,"batch", batch); | ||||||
|  |         field_to_json(Obj,"commonNames", commonNames); | ||||||
|  |         field_to_json(Obj,"completedNames", completedNames); | ||||||
|  |         field_to_json(Obj,"errorNames", errorNames); | ||||||
|  |         field_to_json(Obj,"status", status); | ||||||
|  |         field_to_json(Obj,"command", command); | ||||||
|  |         field_to_json(Obj,"parameters", parameters); | ||||||
|  |         field_to_json(Obj,"submitted", submitted); | ||||||
|  |         field_to_json(Obj,"started", started); | ||||||
|  |         field_to_json(Obj,"completed", completed); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"entity", entity); | ||||||
|  |             field_from_json(Obj,"creator", creator); | ||||||
|  |             field_from_json(Obj,"batch", batch); | ||||||
|  |             field_from_json(Obj,"commonNames", commonNames); | ||||||
|  |             field_from_json(Obj,"completedNames", completedNames); | ||||||
|  |             field_from_json(Obj,"errorNames", errorNames); | ||||||
|  |             field_from_json(Obj,"status", status); | ||||||
|  |             field_from_json(Obj,"command", command); | ||||||
|  |             field_from_json(Obj,"parameters", parameters); | ||||||
|  |             field_from_json(Obj,"submitted", submitted); | ||||||
|  |             field_from_json(Obj,"started", started); | ||||||
|  |             field_from_json(Obj,"completed", completed); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										122
									
								
								src/RESTObjects/RESTAPI_CertObjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/RESTObjects/RESTAPI_CertObjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-07. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  | #include "framework/OpenWifiTypes.h" | ||||||
|  | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi::CertObjects { | ||||||
|  |  | ||||||
|  |     struct CertificateEntry { | ||||||
|  |         OpenWifi::Types::UUID_t         id; | ||||||
|  |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     type; | ||||||
|  |         std::string                     status; | ||||||
|  |         std::string                     certificate; | ||||||
|  |         std::string                     key; | ||||||
|  |         std::string                     devid; | ||||||
|  |         std::string                     cas; | ||||||
|  |         std::string                     manufacturer; | ||||||
|  |         std::string                     model; | ||||||
|  |         std::string                     redirector; | ||||||
|  |         std::string                     commonName; | ||||||
|  |         std::string                     certificateId; | ||||||
|  |         OpenWifi::Types::UUID_t         batch; | ||||||
|  |         uint64_t                        created = 0; | ||||||
|  |         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); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct EntityEntry { | ||||||
|  |         OpenWifi::Types::UUID_t         id; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     name; | ||||||
|  |         std::string                     description; | ||||||
|  |         std::string                     defaultRedirector; | ||||||
|  |         std::string                     apiKey; | ||||||
|  |         std::string                     serverEnrollmentProfile; | ||||||
|  |         std::string                     clientEnrollmentProfile; | ||||||
|  |         std::string                     organization; | ||||||
|  |         SecurityObjects::NoteInfoVec    notes; | ||||||
|  |         bool                            suspended=false; | ||||||
|  |         bool                            deleted=false; | ||||||
|  |         uint64_t                        created = 0 ; | ||||||
|  |         uint64_t                        modified = 0 ; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct BatchEntry { | ||||||
|  |         OpenWifi::Types::UUID_t         id; | ||||||
|  |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     name; | ||||||
|  |         std::string                     description; | ||||||
|  |         std::string                     manufacturer; | ||||||
|  |         std::string                     model; | ||||||
|  |         std::string                     redirector; | ||||||
|  |         std::vector<std::string>        commonNames; | ||||||
|  |         std::vector<std::string>        jobHistory; | ||||||
|  |         SecurityObjects::NoteInfoVec    notes; | ||||||
|  |         uint64_t                        submitted = 0 ; | ||||||
|  |         uint64_t                        started = 0 ; | ||||||
|  |         uint64_t                        completed = 0 ; | ||||||
|  |         uint64_t                        modified = 0 ; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct JobEntry { | ||||||
|  |         OpenWifi::Types::UUID_t         id; | ||||||
|  |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         OpenWifi::Types::UUID_t         batch; | ||||||
|  |         std::string                     command; | ||||||
|  |         OpenWifi::Types::StringVec      commonNames; | ||||||
|  |         OpenWifi::Types::StringVec      completedNames; | ||||||
|  |         OpenWifi::Types::StringVec      errorNames; | ||||||
|  |         Types::StringPairVec            parameters; | ||||||
|  |         std::string                     status; | ||||||
|  |         uint64_t                        submitted=0; | ||||||
|  |         uint64_t                        started=0; | ||||||
|  |         uint64_t                        completed=0; | ||||||
|  |  | ||||||
|  |         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(); |         UnknownFirmwares_.clear(); | ||||||
|         totalSecondsOld_.clear(); |         totalSecondsOld_.clear(); | ||||||
|         numberOfDevices = 0 ; |         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 { |         try { | ||||||
|  |  | ||||||
|             return true; |             return true; | ||||||
| @@ -245,4 +245,65 @@ namespace OpenWifi::FMSObjects { | |||||||
|         } |         } | ||||||
|         return false; |         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> | #include <string> | ||||||
|  |  | ||||||
| #ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H | #pragma once | ||||||
| #define UCENTRALFMS_RESTAPI_FMSOBJECTS_H |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| @@ -127,7 +125,35 @@ namespace OpenWifi::FMSObjects { | |||||||
|         void reset(); |         void reset(); | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         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 |  | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
| #ifdef	TIP_GATEWAY_SERVICE | #ifdef	TIP_GATEWAY_SERVICE | ||||||
| #include "DeviceRegistry.h" | #include "DeviceRegistry.h" | ||||||
|  | #include "CapabilitiesCache.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "RESTAPI_GWobjects.h" | #include "RESTAPI_GWobjects.h" | ||||||
| @@ -26,7 +27,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||||
| #ifdef TIP_GATEWAY_SERVICE | #ifdef TIP_GATEWAY_SERVICE | ||||||
| 		field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible)); | 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); | ||||||
| #endif | #endif | ||||||
| 		field_to_json(Obj,"macAddress", MACAddress); | 		field_to_json(Obj,"macAddress", MACAddress); | ||||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||||
| @@ -44,6 +45,10 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"compatible", Compatible); | 		field_to_json(Obj,"compatible", Compatible); | ||||||
| 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | ||||||
| 		field_to_json(Obj,"devicePassword", DevicePassword); | 		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 { | 	void Device::to_json_with_status(Poco::JSON::Object &Obj) const { | ||||||
| @@ -68,7 +73,7 @@ namespace OpenWifi::GWObjects { | |||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool Device::from_json(Poco::JSON::Object::Ptr &Obj) { | 	bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||||
| 			field_from_json(Obj,"deviceType",DeviceType); | 			field_from_json(Obj,"deviceType",DeviceType); | ||||||
| @@ -80,6 +85,9 @@ namespace OpenWifi::GWObjects { | |||||||
| 			field_from_json(Obj,"location",Location); | 			field_from_json(Obj,"location",Location); | ||||||
| 			field_from_json(Obj,"venue",Venue); | 			field_from_json(Obj,"venue",Venue); | ||||||
| 			field_from_json(Obj,"compatible",Compatible); | 			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; | 			return true; | ||||||
| 		} catch (const Poco::Exception &E) { | 		} catch (const Poco::Exception &E) { | ||||||
| 		} | 		} | ||||||
| @@ -145,9 +153,10 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"custom", Custom); | 		field_to_json(Obj,"custom", Custom); | ||||||
| 		field_to_json(Obj,"waitingForFile", WaitingForFile); | 		field_to_json(Obj,"waitingForFile", WaitingForFile); | ||||||
| 		field_to_json(Obj,"attachFile", AttachDate); | 		field_to_json(Obj,"attachFile", AttachDate); | ||||||
|  | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"name",Name); | 			field_from_json(Obj,"name",Name); | ||||||
| 			field_from_json(Obj,"configuration",Configuration); | 			field_from_json(Obj,"configuration",Configuration); | ||||||
| @@ -166,7 +175,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"created", created); | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | 			field_from_json(Obj,"serialNumber",serialNumber); | ||||||
| 			field_from_json(Obj,"author",author); | 			field_from_json(Obj,"author",author); | ||||||
| @@ -179,7 +188,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); |  | ||||||
| 		field_to_json(Obj,"ipAddress", Address); | 		field_to_json(Obj,"ipAddress", Address); | ||||||
| 		field_to_json(Obj,"txBytes", TX); | 		field_to_json(Obj,"txBytes", TX); | ||||||
| 		field_to_json(Obj,"rxBytes", RX); | 		field_to_json(Obj,"rxBytes", RX); | ||||||
| @@ -190,6 +198,11 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"lastContact", LastContact); | 		field_to_json(Obj,"lastContact", LastContact); | ||||||
| 		field_to_json(Obj,"associations_2G", Associations_2G); | 		field_to_json(Obj,"associations_2G", Associations_2G); | ||||||
| 		field_to_json(Obj,"associations_5G", Associations_5G); | 		field_to_json(Obj,"associations_5G", Associations_5G); | ||||||
|  | 		field_to_json(Obj,"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) { | 		switch(VerifiedCertificate) { | ||||||
| 			case NO_CERTIFICATE: | 			case NO_CERTIFICATE: | ||||||
| @@ -251,7 +264,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		lastContact.clear(); | 		lastContact.clear(); | ||||||
| 		associations.clear(); | 		associations.clear(); | ||||||
| 		numberOfDevices = 0 ; | 		numberOfDevices = 0 ; | ||||||
| 		snapshot = std::time(nullptr); | 		snapshot = OpenWifi::Now(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | ||||||
| @@ -259,5 +272,100 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"capabilities", capabilities); | 		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; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,8 +6,7 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef UCENTRAL_RESTAPI_OBJECTS_H | #pragma once | ||||||
| #define UCENTRAL_RESTAPI_OBJECTS_H |  | ||||||
|  |  | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| @@ -23,7 +22,6 @@ namespace OpenWifi::GWObjects { | |||||||
|  |  | ||||||
| 	struct ConnectionState { | 	struct ConnectionState { | ||||||
| 		uint64_t MessageCount = 0 ; | 		uint64_t MessageCount = 0 ; | ||||||
| 		std::string SerialNumber; |  | ||||||
| 		std::string Address; | 		std::string Address; | ||||||
| 		uint64_t UUID = 0 ; | 		uint64_t UUID = 0 ; | ||||||
| 		uint64_t PendingUUID = 0 ; | 		uint64_t PendingUUID = 0 ; | ||||||
| @@ -35,6 +33,11 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string Firmware; | 		std::string Firmware; | ||||||
| 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | ||||||
| 		std::string Compatible; | 		std::string Compatible; | ||||||
|  | 		uint64_t 	kafkaClients=0; | ||||||
|  | 		uint64_t 	webSocketClients=0; | ||||||
|  | 		uint64_t 	kafkaPackets=0; | ||||||
|  | 		uint64_t 	websocketPackets=0; | ||||||
|  | 		std::string locale; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -50,40 +53,45 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string Firmware; | 		std::string Firmware; | ||||||
| 		std::string Compatible; | 		std::string Compatible; | ||||||
| 		std::string FWUpdatePolicy; | 		std::string FWUpdatePolicy; | ||||||
| 		uint64_t UUID; | 		uint64_t UUID = 0 ; | ||||||
| 		uint64_t CreationTimestamp; | 		uint64_t CreationTimestamp = 0 ; | ||||||
| 		uint64_t LastConfigurationChange; | 		uint64_t LastConfigurationChange = 0 ; | ||||||
| 		uint64_t LastConfigurationDownload; | 		uint64_t LastConfigurationDownload = 0 ; | ||||||
| 		uint64_t LastFWUpdate; | 		uint64_t LastFWUpdate = 0 ; | ||||||
| 		std::string Venue; | 		std::string Venue; | ||||||
| 		std::string DevicePassword; | 		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(Poco::JSON::Object &Obj) const; | ||||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		void Print() const; | 		void Print() const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct Statistics { | 	struct Statistics { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		uint64_t 	UUID; | 		uint64_t 	UUID = 0 ; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Recorded; | 		uint64_t 	Recorded = 0; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct HealthCheck { | 	struct HealthCheck { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		uint64_t 	UUID; | 		uint64_t 	UUID = 0 ; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Recorded; | 		uint64_t 	Recorded = 0 ; | ||||||
| 		uint64_t 	Sanity; | 		uint64_t 	Sanity = 0 ; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct Capabilities { | 	struct Capabilities { | ||||||
| 		std::string Capabilities; | 		std::string Capabilities; | ||||||
| 		uint64_t 	FirstUpdate; | 		uint64_t 	FirstUpdate = 0 ; | ||||||
| 		uint64_t 	LastUpdate; | 		uint64_t 	LastUpdate = 0 ; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -101,22 +109,22 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		std::string Log; | 		std::string Log; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Severity; | 		uint64_t 	Severity = 0 ; | ||||||
| 		uint64_t 	Recorded; | 		uint64_t 	Recorded = 0 ; | ||||||
| 		uint64_t 	LogType; | 		uint64_t 	LogType = 0 ; | ||||||
| 		uint64_t 	UUID; | 		uint64_t 	UUID = 0 ; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct DefaultConfiguration { | 	struct DefaultConfiguration { | ||||||
| 		std::string Name; | 		std::string Name; | ||||||
| 		std::string Configuration; | 		std::string Configuration; | ||||||
| 		std::string Models; | 		Types::StringVec Models; | ||||||
| 		std::string Description; | 		std::string Description; | ||||||
| 		uint64_t 	Created; | 		uint64_t 	Created; | ||||||
| 		uint64_t 	LastModified; | 		uint64_t 	LastModified; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		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 { | 	struct CommandDetails { | ||||||
| @@ -138,6 +146,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		uint64_t AttachDate = 0 ; | 		uint64_t AttachDate = 0 ; | ||||||
| 		uint64_t AttachSize = 0 ; | 		uint64_t AttachSize = 0 ; | ||||||
| 		std::string AttachType; | 		std::string AttachType; | ||||||
|  | 		double 		executionTime = 0.0; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -147,26 +156,26 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string author; | 		std::string author; | ||||||
| 		uint64_t created; | 		uint64_t created; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		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 { | 	struct RttySessionDetails { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		std::string Server; | 		std::string Server; | ||||||
| 		uint64_t 	Port; | 		uint64_t 	Port = 0 ; | ||||||
| 		std::string Token; | 		std::string Token; | ||||||
| 		uint64_t 	TimeOut; | 		uint64_t 	TimeOut = 0 ; | ||||||
| 		std::string ConnectionId; | 		std::string ConnectionId; | ||||||
| 		uint64_t 	Started; | 		uint64_t 	Started = 0 ; | ||||||
| 		std::string CommandUUID; | 		std::string CommandUUID; | ||||||
| 		uint64_t 	ViewPort; | 		uint64_t 	ViewPort = 0 ; | ||||||
| 		std::string DevicePassword; | 		std::string DevicePassword; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct Dashboard { | 	struct Dashboard { | ||||||
| 		uint64_t 		  snapshot; | 		uint64_t 		  snapshot = 0 ; | ||||||
| 		uint64_t 		  numberOfDevices; | 		uint64_t 		  numberOfDevices = 0 ; | ||||||
| 		Types::CountedMap commands; | 		Types::CountedMap commands; | ||||||
| 		Types::CountedMap upTimes; | 		Types::CountedMap upTimes; | ||||||
| 		Types::CountedMap memoryUsed; | 		Types::CountedMap memoryUsed; | ||||||
| @@ -190,6 +199,53 @@ namespace OpenWifi::GWObjects { | |||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif //UCENTRAL_RESTAPI_OBJECTS_H | 	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,"managementPolicy",managementPolicy); | ||||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|         field_to_json( Obj,"devices",devices); |         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,"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) { |     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,"managementPolicy",managementPolicy); | ||||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|             field_from_json( Obj,"devices",devices); |             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,"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; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -142,10 +152,16 @@ namespace OpenWifi::ProvObjects { | |||||||
|         field_to_json( Obj,"design",design); |         field_to_json( Obj,"design",design); | ||||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         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,"location",location); | ||||||
|         field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"deviceRules",deviceRules); | ||||||
|         field_to_json( Obj,"sourceIP",sourceIP); |         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) { |     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,"design",design); | ||||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             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,"location",location); | ||||||
|             field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"deviceRules",deviceRules); | ||||||
|             field_from_json( Obj,"sourceIP",sourceIP); |             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; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
| @@ -171,6 +193,89 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         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 { |     void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json( Obj,"id",id); |         field_to_json( Obj,"id",id); | ||||||
|         field_to_json( Obj,"entity",loginId); |         field_to_json( Obj,"entity",loginId); | ||||||
| @@ -193,6 +298,7 @@ namespace OpenWifi::ProvObjects { | |||||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         field_to_json( Obj,"users",users); |         field_to_json( Obj,"users",users); | ||||||
|         field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|  |         field_to_json( Obj,"venue",venue); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { |     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,"managementPolicy",managementPolicy); | ||||||
|             field_from_json( Obj,"users",users); |             field_from_json( Obj,"users",users); | ||||||
|             field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|  |             field_from_json( Obj,"venue",venue); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|         } |         } | ||||||
| @@ -249,6 +356,92 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         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 { |     void Contact::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         field_to_json( Obj,"type", to_string(type)); |         field_to_json( Obj,"type", to_string(type)); | ||||||
| @@ -295,20 +488,118 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         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 { |     void InventoryTag::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         field_to_json(Obj, "serialNumber", serialNumber); |         field_to_json( Obj, "serialNumber", serialNumber); | ||||||
|         field_to_json(Obj, "venue", venue); |         field_to_json( Obj, "venue", venue); | ||||||
|         field_to_json(Obj, "entity", entity); |         field_to_json( Obj, "entity", entity); | ||||||
|         field_to_json(Obj, "subscriber", subscriber); |         field_to_json( Obj, "subscriber", subscriber); | ||||||
|         field_to_json(Obj, "deviceType", deviceType); |         field_to_json( Obj, "deviceType", deviceType); | ||||||
|         field_to_json(Obj, "qrCode", qrCode); |         field_to_json( Obj, "qrCode", qrCode); | ||||||
|         field_to_json(Obj, "geoCode", geoCode); |         field_to_json( Obj, "geoCode", geoCode); | ||||||
|         field_to_json(Obj, "location", location); |         field_to_json( Obj, "location", location); | ||||||
|         field_to_json(Obj, "contact", contact); |         field_to_json( Obj, "contact", contact); | ||||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         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, "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) { |     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -319,13 +610,17 @@ namespace OpenWifi::ProvObjects { | |||||||
|             field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             field_from_json( Obj,"subscriber",subscriber); |             field_from_json( Obj,"subscriber",subscriber); | ||||||
|             field_from_json( Obj,"deviceType",deviceType); |             field_from_json( Obj,"deviceType",deviceType); | ||||||
|             field_from_json(Obj, "qrCode", qrCode); |             field_from_json( Obj,"qrCode", qrCode); | ||||||
|             field_from_json( Obj,"geoCode",geoCode); |             field_from_json( Obj,"geoCode",geoCode); | ||||||
|             field_from_json( Obj,"location",location); |             field_from_json( Obj,"location",location); | ||||||
|             field_from_json( Obj,"contact",contact); |             field_from_json( Obj,"contact",contact); | ||||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             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,"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; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -333,6 +628,40 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void InventoryConfigApplyResult::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||||
|  |         field_to_json( Obj, "warnings", warnings); | ||||||
|  |         field_to_json( Obj, "errors", errors); | ||||||
|  |         field_to_json( Obj, "errorCode", errorCode); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool InventoryConfigApplyResult::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||||
|  |             field_from_json( Obj, "warnings", warnings); | ||||||
|  |             field_from_json( Obj, "errors", errors); | ||||||
|  |             field_from_json( Obj, "errorCode", errorCode); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void InventoryTagList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json( Obj,"taglist",taglist); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json( Obj,"taglist",taglist); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { |     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json( Obj,"name", name); |         field_to_json( Obj,"name", name); | ||||||
|         field_to_json( Obj,"description", description); |         field_to_json( Obj,"description", description); | ||||||
| @@ -357,12 +686,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         field_to_json( Obj,"deviceTypes",deviceTypes); |         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,"configuration",configuration); | ||||||
|         field_to_json( Obj,"inUse",inUse); |         field_to_json( Obj,"inUse",inUse); | ||||||
|         field_to_json( Obj,"variables",variables); |         field_to_json( Obj,"variables",variables); | ||||||
|         field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"deviceRules",deviceRules); | ||||||
|         field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); |  | ||||||
|         field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -370,12 +701,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             field_from_json( Obj,"deviceTypes",deviceTypes); |             field_from_json( Obj,"deviceTypes",deviceTypes); | ||||||
|             field_from_json( Obj,"configuration",configuration); |  | ||||||
|             field_from_json( Obj,"inUse",inUse); |             field_from_json( Obj,"inUse",inUse); | ||||||
|             field_from_json( Obj,"variables",variables); |             field_from_json( Obj,"variables",variables); | ||||||
|             field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"subscriberOnly",subscriberOnly); | ||||||
|             field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); |             field_from_json( Obj,"entity", entity); | ||||||
|             field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); |             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; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -440,11 +773,11 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UserList::to_json(Poco::JSON::Object &Obj) const { |     void UuidList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj, "list", list); |         field_to_json(Obj, "list", list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool UserList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool UuidList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj, "list", list); |             field_from_json(Obj, "list", list); | ||||||
|             return true; |             return true; | ||||||
| @@ -456,12 +789,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { |     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj, "users", users); |         field_to_json(Obj, "users", users); | ||||||
|  |         field_to_json(Obj, "roles", roles); | ||||||
|         field_to_json(Obj, "access", access); |         field_to_json(Obj, "access", access); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj, "users", users); |             field_from_json(Obj, "users", users); | ||||||
|  |             field_from_json(Obj, "roles", roles); | ||||||
|             field_from_json(Obj, "access", access); |             field_from_json(Obj, "access", access); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
| @@ -491,16 +826,34 @@ namespace OpenWifi::ProvObjects { | |||||||
|         field_to_json( Obj,"creator",creator); |         field_to_json( Obj,"creator",creator); | ||||||
|         field_to_json( Obj,"visibility",visibility); |         field_to_json( Obj,"visibility",visibility); | ||||||
|         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) { |     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             field_from_json( Obj,"data",data); |             RESTAPI_utils::field_from_json( Obj,"data",data); | ||||||
|             field_from_json( Obj,"entity",entity); |             RESTAPI_utils::field_from_json( Obj,"entity",entity); | ||||||
|             field_from_json( Obj,"creator",creator); |             RESTAPI_utils::field_from_json( Obj,"creator",creator); | ||||||
|             field_from_json( Obj,"visibility",visibility); |             RESTAPI_utils::field_from_json( Obj,"visibility",visibility); | ||||||
|             field_from_json( Obj,"access",access); |             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; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -509,12 +862,227 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void MapList::to_json(Poco::JSON::Object &Obj) const { |     void MapList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json( Obj,"list",list); |         RESTAPI_utils::field_to_json( Obj,"list",list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json( Obj,"list",list); |             RESTAPI_utils::field_from_json( Obj,"list",list); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         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; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -523,14 +1091,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { |     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||||
|         uint64_t Now = std::time(nullptr); |         uint64_t Now = OpenWifi::Now(); | ||||||
|         if(O->has("name")) |         if(O->has("name")) | ||||||
|             I.name = O->get("name").toString(); |             I.name = O->get("name").toString(); | ||||||
|  |  | ||||||
|         if(I.name.empty()) |         if(I.name.empty()) | ||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
|        if(O->has("description")) |         if(O->has("description")) | ||||||
|             I.description = O->get("description").toString(); |             I.description = O->get("description").toString(); | ||||||
|         SecurityObjects::MergeNotes(O,U,I.notes); |         SecurityObjects::MergeNotes(O,U,I.notes); | ||||||
|         SecurityObjects::NoteInfoVec N; |         SecurityObjects::NoteInfoVec N; | ||||||
| @@ -544,7 +1112,7 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { |     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||||
|         uint64_t Now = std::time(nullptr); |         uint64_t Now = OpenWifi::Now(); | ||||||
|         if(O->has("name")) |         if(O->has("name")) | ||||||
|             I.name = O->get("name").toString(); |             I.name = O->get("name").toString(); | ||||||
|  |  | ||||||
| @@ -566,4 +1134,30 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|         return true; |         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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,9 +6,7 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
| #ifndef OWPROV_RESTAPI_PROVOBJECTS_H |  | ||||||
| #define OWPROV_RESTAPI_PROVOBJECTS_H |  | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| @@ -35,6 +33,13 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         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 { |     struct ManagementPolicyEntry { | ||||||
|         Types::UUIDvec_t users; |         Types::UUIDvec_t users; | ||||||
|         Types::UUIDvec_t resources; |         Types::UUIDvec_t resources; | ||||||
| @@ -50,12 +55,22 @@ namespace OpenWifi::ProvObjects { | |||||||
|         std::vector<ManagementPolicyEntry>  entries; |         std::vector<ManagementPolicyEntry>  entries; | ||||||
|         Types::StringVec    inUse; |         Types::StringVec    inUse; | ||||||
|         Types::UUID_t       entity; |         Types::UUID_t       entity; | ||||||
|  |         Types::UUID_t       venue; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|     typedef std::vector<ManagementPolicy>      ManagementPolicyVec; |     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 { |     struct Entity { | ||||||
|         ObjectInfo              info; |         ObjectInfo              info; | ||||||
|         Types::UUID_t           parent; |         Types::UUID_t           parent; | ||||||
| @@ -66,8 +81,13 @@ namespace OpenWifi::ProvObjects { | |||||||
|         Types::UUID_t           managementPolicy; |         Types::UUID_t           managementPolicy; | ||||||
|         Types::UUIDvec_t        deviceConfiguration; |         Types::UUIDvec_t        deviceConfiguration; | ||||||
|         Types::UUIDvec_t        devices; |         Types::UUIDvec_t        devices; | ||||||
|         std::string             rrm; |         DeviceRules             deviceRules; | ||||||
|         Types::StringVec        sourceIP; |         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; |         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); | ||||||
| @@ -94,10 +114,16 @@ namespace OpenWifi::ProvObjects { | |||||||
|         DiGraph             topology; |         DiGraph             topology; | ||||||
|         std::string         design; |         std::string         design; | ||||||
|         Types::UUIDvec_t    deviceConfiguration; |         Types::UUIDvec_t    deviceConfiguration; | ||||||
|         std::string         contact; |         Types::UUIDvec_t    contacts; | ||||||
|         std::string         location; |         std::string         location; | ||||||
|         std::string         rrm; |         DeviceRules         deviceRules; | ||||||
|         Types::StringVec    sourceIP; |         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; |         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); | ||||||
| @@ -119,6 +145,7 @@ namespace OpenWifi::ProvObjects { | |||||||
|         Types::UUIDvec_t    users; |         Types::UUIDvec_t    users; | ||||||
|         Types::StringVec    inUse; |         Types::StringVec    inUse; | ||||||
|         Types::UUID_t       entity; |         Types::UUID_t       entity; | ||||||
|  |         Types::UUID_t       venue; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -182,6 +209,51 @@ namespace OpenWifi::ProvObjects { | |||||||
|     }; |     }; | ||||||
|     typedef std::vector<Location>      LocationVec; |     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 { |     enum ContactType { | ||||||
|         CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER, |         CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER, | ||||||
|         CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN |         CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN | ||||||
| @@ -245,6 +317,55 @@ namespace OpenWifi::ProvObjects { | |||||||
|     }; |     }; | ||||||
|     typedef std::vector<Contact>      ContactVec; |     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 { |     struct DeviceConfigurationElement { | ||||||
|         std::string name; |         std::string name; | ||||||
|         std::string description; |         std::string description; | ||||||
| @@ -257,21 +378,24 @@ namespace OpenWifi::ProvObjects { | |||||||
|     typedef std::vector<DeviceConfigurationElement> DeviceConfigurationElementVec; |     typedef std::vector<DeviceConfigurationElement> DeviceConfigurationElementVec; | ||||||
|  |  | ||||||
|     struct DeviceConfiguration { |     struct DeviceConfiguration { | ||||||
|     ObjectInfo                          info; |         ObjectInfo                      info; | ||||||
|         Types::UUID_t                   managementPolicy; |         Types::UUID_t                   managementPolicy; | ||||||
|         Types::StringVec                deviceTypes; |         Types::StringVec                deviceTypes; | ||||||
|         DeviceConfigurationElementVec   configuration; |         DeviceConfigurationElementVec   configuration; | ||||||
|         Types::StringVec                inUse; |         Types::StringVec                inUse; | ||||||
|         Types::StringPairVec            variables; |         Types::UUIDvec_t                variables; | ||||||
|         std::string                     rrm; |         DeviceRules                     deviceRules; | ||||||
|         std::string                     firmwareUpgrade; |         bool                            subscriberOnly=false; | ||||||
|         bool                            firmwareRCOnly=false; |         std::string                     venue; | ||||||
|  |         std::string                     entity; | ||||||
|  |         std::string                     subscriber; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|     typedef std::vector<DeviceConfiguration>      DeviceConfigurationVec; |     typedef std::vector<DeviceConfiguration>      DeviceConfigurationVec; | ||||||
|  |  | ||||||
|  |  | ||||||
|     struct InventoryTag { |     struct InventoryTag { | ||||||
|         ObjectInfo      info; |         ObjectInfo      info; | ||||||
|         std::string     serialNumber; |         std::string     serialNumber; | ||||||
| @@ -284,14 +408,36 @@ namespace OpenWifi::ProvObjects { | |||||||
|         std::string     location; |         std::string     location; | ||||||
|         std::string     contact; |         std::string     contact; | ||||||
|         std::string     deviceConfiguration; |         std::string     deviceConfiguration; | ||||||
|         std::string     rrm; |         DeviceRules     deviceRules; | ||||||
|         Types::UUID_t   managementPolicy; |         Types::UUID_t   managementPolicy; | ||||||
|  |         std::string     state; | ||||||
|  |         std::string     devClass; | ||||||
|  |         std::string     locale; | ||||||
|  |         std::string     realMacAddress; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     typedef std::vector<InventoryTag>      InventoryTagVec; |     typedef std::vector<InventoryTag>      InventoryTagVec; | ||||||
|  |  | ||||||
|  |     struct InventoryTagList { | ||||||
|  |         InventoryTagVec     taglist; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         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 { |     struct Report { | ||||||
|         uint64_t            snapShot=0; |         uint64_t            snapShot=0; | ||||||
|         Types::CountedMap   tenants; |         Types::CountedMap   tenants; | ||||||
| @@ -324,16 +470,21 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct UserList { |     struct UuidList { | ||||||
|         std::vector<std::string>    list; |         Types::UUIDvec_t    list; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     enum ACLACCESS { | ||||||
|  |         NONE = 0, READ=1, MODIFY=2, CREATE=3, DELETE=4 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     struct ObjectACL { |     struct ObjectACL { | ||||||
|         UserList        users; |         UuidList        users; | ||||||
|         std::string     access; |         UuidList        roles; | ||||||
|  |         uint64_t        access = (uint64_t) NONE; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -351,8 +502,10 @@ namespace OpenWifi::ProvObjects { | |||||||
|         std::string         data; |         std::string         data; | ||||||
|         std::string         entity; |         std::string         entity; | ||||||
|         std::string         creator; |         std::string         creator; | ||||||
|         std::string         visibility; |         std::string         visibility{"private"}; | ||||||
|         ObjectACLList       access; |         ObjectACLList       access; | ||||||
|  |         Types::UUID_t       managementPolicy; | ||||||
|  |         std::string         venue; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -365,10 +518,168 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         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 UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); |     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|  |     bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif //OWPROV_RESTAPI_PROVOBJECTS_H |  | ||||||
|   | |||||||
| @@ -54,6 +54,8 @@ namespace OpenWifi::SecurityObjects { | |||||||
|             return ADMIN; |             return ADMIN; | ||||||
|         else if (!Poco::icompare(U,"subscriber")) |         else if (!Poco::icompare(U,"subscriber")) | ||||||
|             return SUBSCRIBER; |             return SUBSCRIBER; | ||||||
|  |         else if (!Poco::icompare(U,"partner")) | ||||||
|  |             return PARTNER; | ||||||
|         else if (!Poco::icompare(U,"csr")) |         else if (!Poco::icompare(U,"csr")) | ||||||
|             return CSR; |             return CSR; | ||||||
|         else if (!Poco::icompare(U, "system")) |         else if (!Poco::icompare(U, "system")) | ||||||
| @@ -72,6 +74,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|             case ROOT: return "root"; |             case ROOT: return "root"; | ||||||
|             case ADMIN: return "admin"; |             case ADMIN: return "admin"; | ||||||
|             case SUBSCRIBER: return "subscriber"; |             case SUBSCRIBER: return "subscriber"; | ||||||
|  |             case PARTNER: return "partner"; | ||||||
|             case CSR: return "csr"; |             case CSR: return "csr"; | ||||||
|             case SYSTEM: return "system"; |             case SYSTEM: return "system"; | ||||||
|             case INSTALLER: return "installer"; |             case INSTALLER: return "installer"; | ||||||
| @@ -92,6 +95,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "PortalLogin", PortalLogin_); | 			field_from_json(Obj, "PortalLogin", PortalLogin_); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: AclTemplate" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -109,6 +113,8 @@ namespace OpenWifi::SecurityObjects { | |||||||
|         field_to_json(Obj,"userMustChangePassword",userMustChangePassword); |         field_to_json(Obj,"userMustChangePassword",userMustChangePassword); | ||||||
|         field_to_json(Obj,"errorCode", errorCode); |         field_to_json(Obj,"errorCode", errorCode); | ||||||
| 		Obj.set("aclTemplate",AclTemplateObj); | 		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) { | 	bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -125,9 +131,10 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "created", created_); | 			field_from_json(Obj, "created", created_); | ||||||
| 			field_from_json(Obj, "username", username_); | 			field_from_json(Obj, "username", username_); | ||||||
|             field_from_json(Obj, "userMustChangePassword",userMustChangePassword); |             field_from_json(Obj, "userMustChangePassword",userMustChangePassword); | ||||||
|  |             field_from_json(Obj,"lastRefresh", lastRefresh_); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (...) { | 		} catch (...) { | ||||||
|  |             std::cout << "Cannot parse: WebToken" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -138,14 +145,14 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"primary", primary); | 	    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 { | 	    try { | ||||||
| 	        field_from_json(Obj,"number",number); | 	        field_from_json(Obj,"number",number); | ||||||
| 	        field_from_json(Obj,"verified",verified); | 	        field_from_json(Obj,"verified",verified); | ||||||
| 	        field_from_json(Obj,"primary",primary); | 	        field_from_json(Obj,"primary",primary); | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch (...) { | 	    } catch (...) { | ||||||
|  |             std::cout << "Cannot parse: MobilePhoneNumber" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	}; | 	}; | ||||||
| @@ -155,13 +162,13 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"method", method); | 	    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 { | 	    try { | ||||||
| 	        field_from_json(Obj,"enabled",enabled); | 	        field_from_json(Obj,"enabled",enabled); | ||||||
| 	        field_from_json(Obj,"method",method); | 	        field_from_json(Obj,"method",method); | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch (...) { | 	    } catch (...) { | ||||||
|  |             std::cout << "Cannot parse: MfaAuthInfo" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	} | 	} | ||||||
| @@ -169,15 +176,17 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { | 	void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 	    field_to_json(Obj, "mobiles", mobiles); | 	    field_to_json(Obj, "mobiles", mobiles); | ||||||
| 	    field_to_json(Obj, "mfa", mfa); | 	    field_to_json(Obj, "mfa", mfa); | ||||||
|  |         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 { | 	    try { | ||||||
| 	        field_from_json(Obj,"mobiles",mobiles); | 	        field_from_json(Obj, "mobiles",mobiles); | ||||||
| 	        field_from_json(Obj,"mfa",mfa); | 	        field_from_json(Obj, "mfa",mfa); | ||||||
|  |             field_from_json(Obj, "authenticatorSecret", authenticatorSecret); | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch (...) { | 	    } catch (...) { | ||||||
|  |             std::cout << "Cannot parse: UserLoginLoginExtensions" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	} | 	} | ||||||
| @@ -189,7 +198,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|         field_to_json(Obj, "method", method); |         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 { | 	    try { | ||||||
| 	        field_from_json(Obj,"uuid",uuid); | 	        field_from_json(Obj,"uuid",uuid); | ||||||
| 	        field_from_json(Obj,"question",question); | 	        field_from_json(Obj,"question",question); | ||||||
| @@ -197,7 +206,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	        field_from_json(Obj,"method",method); | 	        field_from_json(Obj,"method",method); | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch (...) { | 	    } catch (...) { | ||||||
|  |             std::cout << "Cannot parse: MFAChallengeRequest" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	}; | 	}; | ||||||
| @@ -205,23 +214,22 @@ namespace OpenWifi::SecurityObjects { | |||||||
|     void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const { |     void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj, "uuid", uuid); |         field_to_json(Obj, "uuid", uuid); | ||||||
|         field_to_json(Obj, "answer", answer); |         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 { |         try { | ||||||
|             field_from_json(Obj,"uuid",uuid); |             field_from_json(Obj,"uuid",uuid); | ||||||
|             field_from_json(Obj,"answer",answer); |             field_from_json(Obj,"answer",answer); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |             std::cout << "Cannot parse: MFAChallengeResponse" << std::endl; | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UserInfo::to_json(Poco::JSON::Object &Obj) const { |     void UserInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"Id",Id); | 		field_to_json(Obj,"id",id); | ||||||
| 		field_to_json(Obj,"name",name); | 		field_to_json(Obj,"name",name); | ||||||
| 		field_to_json(Obj,"description", description); | 		field_to_json(Obj,"description", description); | ||||||
| 		field_to_json(Obj,"avatar", avatar); | 		field_to_json(Obj,"avatar", avatar); | ||||||
| @@ -251,11 +259,13 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"lastPasswords",lastPasswords); | 		field_to_json(Obj,"lastPasswords",lastPasswords); | ||||||
| 		field_to_json(Obj,"oauthType",oauthType); | 		field_to_json(Obj,"oauthType",oauthType); | ||||||
| 		field_to_json(Obj,"oauthUserInfo",oauthUserInfo); | 		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) { |     bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
| 			field_from_json(Obj,"Id",Id); | 			field_from_json(Obj,"id",id); | ||||||
| 			field_from_json(Obj,"name",name); | 			field_from_json(Obj,"name",name); | ||||||
| 			field_from_json(Obj,"description",description); | 			field_from_json(Obj,"description",description); | ||||||
| 			field_from_json(Obj,"avatar",avatar); | 			field_from_json(Obj,"avatar",avatar); | ||||||
| @@ -265,6 +275,8 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"currentLoginURI",currentLoginURI); | 			field_from_json(Obj,"currentLoginURI",currentLoginURI); | ||||||
| 			field_from_json(Obj,"locale",locale); | 			field_from_json(Obj,"locale",locale); | ||||||
| 			field_from_json(Obj,"notes",notes); | 			field_from_json(Obj,"notes",notes); | ||||||
|  |             field_from_json(Obj,"location", location); | ||||||
|  |             field_from_json(Obj,"owner", owner); | ||||||
| 			field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString); | 			field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString); | ||||||
| 			field_from_json(Obj,"securityPolicy",securityPolicy); | 			field_from_json(Obj,"securityPolicy",securityPolicy); | ||||||
| 			field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); | 			field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); | ||||||
| @@ -283,13 +295,29 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"lastPasswords",lastPasswords); | 			field_from_json(Obj,"lastPasswords",lastPasswords); | ||||||
| 			field_from_json(Obj,"oauthType",oauthType); | 			field_from_json(Obj,"oauthType",oauthType); | ||||||
| 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||||
|  |             field_from_json(Obj,"modified",modified); | ||||||
|  |             field_from_json(Obj,"signingUp",signingUp); | ||||||
|             return true; |             return true; | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|  |             std::cout << "Cannot parse: UserInfo" << std::endl; | ||||||
|         } |         } | ||||||
|         return false; |         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 { | 	void InternalServiceInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"privateURI",privateURI); | 		field_to_json(Obj,"privateURI",privateURI); | ||||||
| 		field_to_json(Obj,"publicURI",publicURI); | 		field_to_json(Obj,"publicURI",publicURI); | ||||||
| @@ -303,7 +331,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"token",token); | 			field_from_json(Obj,"token",token); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (...) { | 		} catch (...) { | ||||||
|  |             std::cout << "Cannot parse: InternalServiceInfo" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	}; | 	}; | ||||||
| @@ -321,7 +349,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "services", services); | 			field_from_json(Obj, "services", services); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: InternalSystemServices" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	}; | 	}; | ||||||
| @@ -343,7 +371,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "authenticationType", authenticationType); | 			field_from_json(Obj, "authenticationType", authenticationType); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (...) { | 		} catch (...) { | ||||||
|  |             std::cout << "Cannot parse: SystemEndpoint" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	}; | 	}; | ||||||
| @@ -357,7 +385,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "endpoints", endpoints); | 			field_from_json(Obj, "endpoints", endpoints); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (...) { | 		} catch (...) { | ||||||
|  |             std::cout << "Cannot parse: SystemEndpointList" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -376,7 +404,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj, "userInfo", userinfo); | 			field_from_json(Obj, "userInfo", userinfo); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: UserInfoAndPolicy" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -387,14 +415,14 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"note", note); | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"created",created); |             field_from_json(Obj,"created",created); | ||||||
| 			field_from_json(Obj,"createdBy",createdBy); | 			field_from_json(Obj,"createdBy",createdBy); | ||||||
| 			field_from_json(Obj,"note",note); | 			field_from_json(Obj,"note", note); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: NoteInfo" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -405,20 +433,20 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	            SecurityObjects::NoteInfoVec NIV; | 	            SecurityObjects::NoteInfoVec NIV; | ||||||
| 	            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString()); | 	            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString()); | ||||||
| 	            for(auto const &i:NIV) { | 	            for(auto const &i:NIV) { | ||||||
| 	                SecurityObjects::NoteInfo   ii{.created=(uint64_t)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); | 	                Notes.push_back(ii); | ||||||
| 	            } | 	            } | ||||||
| 	        } | 	        } | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch(...) { | 	    } catch(...) { | ||||||
|  |             std::cout << "Cannot parse: MergeNotes" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { | 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { | ||||||
| 	    for(auto const &i:NewNotes) { | 	    for(auto const &i:NewNotes) { | ||||||
| 	        SecurityObjects::NoteInfo   ii{.created=(uint64_t)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); | 	        ExistingNotes.push_back(ii); | ||||||
| 	    } | 	    } | ||||||
|         return true; |         return true; | ||||||
| @@ -429,13 +457,13 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"resource",resource); | 			field_from_json(Obj,"resource",resource); | ||||||
| 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: ProfileAction" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -449,7 +477,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"notes", notes); | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"id",id); | 			field_from_json(Obj,"id",id); | ||||||
| 			field_from_json(Obj,"name",name); | 			field_from_json(Obj,"name",name); | ||||||
| @@ -459,7 +487,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"notes",notes); | 			field_from_json(Obj,"notes",notes); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: SecurityProfile" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -468,12 +496,12 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj, "profiles", profiles); | 		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 { | 		try { | ||||||
| 			field_from_json(Obj,"profiles",profiles); | 			field_from_json(Obj,"profiles",profiles); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |             std::cout << "Cannot parse: SecurityProfileList" << std::endl; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -491,10 +519,10 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"expires",expires); | 	    field_to_json(Obj,"expires",expires); | ||||||
| 	    field_to_json(Obj,"completed",completed); | 	    field_to_json(Obj,"completed",completed); | ||||||
| 	    field_to_json(Obj,"canceled",canceled); | 	    field_to_json(Obj,"canceled",canceled); | ||||||
|  |         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 { | 	    try { | ||||||
| 	        field_from_json(Obj,"id",id); | 	        field_from_json(Obj,"id",id); | ||||||
| 	        field_from_json(Obj,"action",action); | 	        field_from_json(Obj,"action",action); | ||||||
| @@ -508,11 +536,88 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	        field_from_json(Obj,"expires",expires); | 	        field_from_json(Obj,"expires",expires); | ||||||
| 	        field_from_json(Obj,"completed",completed); | 	        field_from_json(Obj,"completed",completed); | ||||||
| 	        field_from_json(Obj,"canceled",canceled); | 	        field_from_json(Obj,"canceled",canceled); | ||||||
|  |             field_from_json(Obj,"userAction",userAction); | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch(...) { | 	    } catch(...) { | ||||||
|  |             std::cout << "Cannot parse: ActionLink" << std::endl; | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |     void Preferences::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  | 	    field_to_json(Obj,"id",id); | ||||||
|  | 	    field_to_json(Obj,"modified",modified); | ||||||
|  | 	    field_to_json(Obj,"data",data); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     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; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  | 	    field_to_json(Obj,"id",id); | ||||||
|  | 	    field_to_json(Obj,"type",type); | ||||||
|  | 	    field_to_json(Obj,"sms",sms); | ||||||
|  | 	    field_to_json(Obj,"email",email); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     bool SubMfaConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  | 	    try { | ||||||
|  | 	        field_from_json(Obj,"id",id); | ||||||
|  | 	        field_from_json(Obj,"type",type); | ||||||
|  | 	        field_from_json(Obj,"sms",sms); | ||||||
|  | 	        field_from_json(Obj,"email",email); | ||||||
|  | 	        return true; | ||||||
|  | 	    } catch(...) { | ||||||
|  |             std::cout << "Cannot parse: SubMfaConfig" << std::endl; | ||||||
|  | 	    } | ||||||
|  | 	    return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     void Token::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"token",token); | ||||||
|  |         field_to_json(Obj,"refreshToken",refreshToken); | ||||||
|  |         field_to_json(Obj,"tokenType",tokenType); | ||||||
|  |         field_to_json(Obj,"userName",userName); | ||||||
|  |         field_to_json(Obj,"created",created); | ||||||
|  |         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(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"token",token); | ||||||
|  |             field_from_json(Obj,"refreshToken",refreshToken); | ||||||
|  |             field_from_json(Obj,"tokenType",tokenType); | ||||||
|  |             field_from_json(Obj,"userName",userName); | ||||||
|  |             field_from_json(Obj,"created",created); | ||||||
|  |             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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void LoginRecordInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"sessionId",sessionId); | ||||||
|  |         field_to_json(Obj,"userId",userId); | ||||||
|  |         field_to_json(Obj,"email",email); | ||||||
|  |         field_to_json(Obj,"login",login); | ||||||
|  |         field_to_json(Obj,"logout",logout); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,244 +6,322 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef UCENTRAL_RESTAPI_SECURITYOBJECTS_H | #pragma once | ||||||
| #define UCENTRAL_RESTAPI_SECURITYOBJECTS_H |  | ||||||
|  |  | ||||||
| #include "Poco/JSON/Object.h" | #include <string> | ||||||
|  | #include <type_traits> | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
|  | #include "Poco/JSON/Object.h" | ||||||
|  | #include "Poco/Data/LOB.h" | ||||||
|  | #include "Poco/Data/LOBStream.h" | ||||||
|  |  | ||||||
| namespace OpenWifi::SecurityObjects { | namespace OpenWifi { | ||||||
|  |     uint64_t Now(); | ||||||
|  |     namespace SecurityObjects { | ||||||
|  |          | ||||||
|  |         typedef std::string USER_ID_TYPE; | ||||||
|  |  | ||||||
| 	struct AclTemplate { |         struct AclTemplate { | ||||||
| 		bool Read_ = true; |             bool Read_ = true; | ||||||
| 		bool ReadWrite_ = true; |             bool ReadWrite_ = true; | ||||||
| 		bool ReadWriteCreate_ = true; |             bool ReadWriteCreate_ = true; | ||||||
| 		bool Delete_ = true; |             bool Delete_ = true; | ||||||
| 		bool PortalLogin_ = true; |             bool PortalLogin_ = true; | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |             AclTemplate()  noexcept = default; | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; |  | ||||||
|  |  | ||||||
| 	struct WebToken { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		std::string access_token_; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		std::string refresh_token_; |         }; | ||||||
| 		std::string id_token_; |  | ||||||
| 		std::string token_type_; |  | ||||||
| 		std::string username_; |  | ||||||
| 		bool userMustChangePassword=false; |  | ||||||
|         uint64_t errorCode=0; |  | ||||||
| 		uint64_t expires_in_=0; |  | ||||||
| 		uint64_t idle_timeout_=0; |  | ||||||
| 		AclTemplate acl_template_; |  | ||||||
| 		uint64_t created_=0; |  | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |         static_assert( std::is_nothrow_move_constructible_v<AclTemplate> ); | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
|     enum USER_ROLE { |         struct WebToken { | ||||||
|         UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING |             std::string access_token_; | ||||||
|     }; |             std::string refresh_token_; | ||||||
|  |             std::string id_token_; | ||||||
|  |             std::string token_type_; | ||||||
|  |             std::string username_; | ||||||
|  |             bool userMustChangePassword=false; | ||||||
|  |             uint64_t errorCode=0; | ||||||
|  |             uint64_t expires_in_=0; | ||||||
|  |             uint64_t idle_timeout_=0; | ||||||
|  |             AclTemplate acl_template_; | ||||||
|  |             uint64_t created_=0; | ||||||
|  |             uint64_t lastRefresh_=0; | ||||||
|  |  | ||||||
|     USER_ROLE UserTypeFromString(const std::string &U); |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|     std::string UserTypeToString(USER_ROLE U); |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|     struct NoteInfo { |         enum USER_ROLE { | ||||||
| 		uint64_t created = std::time(nullptr); |             UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER | ||||||
| 		std::string createdBy; |         }; | ||||||
| 		std::string note; |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
| 	typedef std::vector<NoteInfo>	NoteInfoVec; |  | ||||||
|  |  | ||||||
| 	struct MobilePhoneNumber { |         USER_ROLE UserTypeFromString(const std::string &U); | ||||||
| 	    std::string number; |         std::string UserTypeToString(USER_ROLE U); | ||||||
| 	    bool verified = false; |  | ||||||
| 	    bool primary = false; |  | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; |         struct NoteInfo { | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); |             uint64_t    created=0; // = OpenWifi::Now(); | ||||||
| 	}; |             std::string createdBy; | ||||||
|  |             std::string note; | ||||||
|  |  | ||||||
| 	struct MfaAuthInfo { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	    bool enabled = false; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 	    std::string method; |         }; | ||||||
|  |         typedef std::vector<NoteInfo>	NoteInfoVec; | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; |         struct MobilePhoneNumber { | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); |             std::string number; | ||||||
| 	}; |             bool verified = false; | ||||||
|  |             bool primary = false; | ||||||
|  |  | ||||||
| 	struct UserLoginLoginExtensions { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	    std::vector<MobilePhoneNumber>  mobiles; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 	    struct MfaAuthInfo mfa; |         }; | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; |         struct MfaAuthInfo { | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); |             bool enabled = false; | ||||||
| 	}; |             std::string method; | ||||||
|  |  | ||||||
| 	struct MFAChallengeRequest { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	    std::string uuid; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 	    std::string question; |         }; | ||||||
| 	    std::string method; |  | ||||||
| 	    uint64_t    created = std::time(nullptr); |  | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; |         struct UserLoginLoginExtensions { | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); |             std::vector<MobilePhoneNumber>  mobiles; | ||||||
| 	}; |             struct MfaAuthInfo              mfa; | ||||||
|  |             std::string                     authenticatorSecret; | ||||||
|  |  | ||||||
|     struct MFAChallengeResponse { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         std::string uuid; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|         std::string answer; |         }; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         struct MFAChallengeRequest { | ||||||
|         bool from_json(Poco::JSON::Object::Ptr &Obj); |             std::string uuid; | ||||||
|     }; |             std::string question; | ||||||
|  |             std::string method; | ||||||
|  |             uint64_t    created = OpenWifi::Now(); | ||||||
|  |  | ||||||
| 	struct UserInfo { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         std::string Id; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		std::string name; |         }; | ||||||
| 		std::string description; |  | ||||||
| 		std::string avatar; |  | ||||||
| 		std::string email; |  | ||||||
| 		bool validated = false; |  | ||||||
| 		std::string validationEmail; |  | ||||||
| 		uint64_t validationDate = 0; |  | ||||||
| 		uint64_t creationDate = 0; |  | ||||||
| 		std::string validationURI; |  | ||||||
| 		bool changePassword = false; |  | ||||||
| 		uint64_t lastLogin = 0; |  | ||||||
| 		std::string currentLoginURI; |  | ||||||
| 		uint64_t lastPasswordChange = 0; |  | ||||||
| 		uint64_t lastEmailCheck = 0; |  | ||||||
| 		bool waitingForEmailCheck = false; |  | ||||||
| 		std::string locale; |  | ||||||
| 		NoteInfoVec notes; |  | ||||||
| 		std::string location; |  | ||||||
| 		std::string owner; |  | ||||||
| 		bool suspended = false; |  | ||||||
| 		bool blackListed = false; |  | ||||||
|         USER_ROLE userRole; |  | ||||||
|         UserLoginLoginExtensions userTypeProprietaryInfo; |  | ||||||
| 		std::string securityPolicy; |  | ||||||
| 		uint64_t securityPolicyChange = 0 ; |  | ||||||
| 		std::string currentPassword; |  | ||||||
| 		Types::StringVec lastPasswords; |  | ||||||
| 		std::string oauthType; |  | ||||||
| 		std::string oauthUserInfo; |  | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |         struct MFAChallengeResponse { | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |             std::string uuid; | ||||||
| 	}; |             std::string answer; | ||||||
| 	typedef std::vector<UserInfo>   UserInfoVec; |  | ||||||
|  |  | ||||||
| 	// bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); |         }; | ||||||
|  |  | ||||||
| 	struct InternalServiceInfo { |         struct UserInfo { | ||||||
| 		std::string privateURI; |             std::string id; | ||||||
| 		std::string publicURI; |             std::string name; | ||||||
| 		std::string token; |             std::string description; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |             std::string avatar; | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |             std::string email; | ||||||
| 	}; |             bool        validated = false; | ||||||
| 	typedef std::vector<InternalServiceInfo>	InternalServiceInfoVec; |             std::string validationEmail; | ||||||
|  |             uint64_t    validationDate = 0; | ||||||
|  |             uint64_t    creationDate = 0; | ||||||
|  |             std::string validationURI; | ||||||
|  |             bool        changePassword = false; | ||||||
|  |             uint64_t    lastLogin = 0; | ||||||
|  |             std::string currentLoginURI; | ||||||
|  |             uint64_t    lastPasswordChange = 0; | ||||||
|  |             uint64_t    lastEmailCheck = 0; | ||||||
|  |             bool        waitingForEmailCheck = false; | ||||||
|  |             std::string locale; | ||||||
|  |             NoteInfoVec notes; | ||||||
|  |             std::string location; | ||||||
|  |             std::string owner; | ||||||
|  |             bool        suspended = false; | ||||||
|  |             bool        blackListed = false; | ||||||
|  |             USER_ROLE   userRole; | ||||||
|  |             UserLoginLoginExtensions userTypeProprietaryInfo; | ||||||
|  |             std::string securityPolicy; | ||||||
|  |             uint64_t    securityPolicyChange = 0 ; | ||||||
|  |             std::string currentPassword; | ||||||
|  |             OpenWifi::Types::StringVec lastPasswords; | ||||||
|  |             std::string oauthType; | ||||||
|  |             std::string oauthUserInfo; | ||||||
|  |             uint64_t    modified; | ||||||
|  |             std::string signingUp; | ||||||
|  |  | ||||||
| 	struct InternalSystemServices { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		std::string key; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		std::string version; |         }; | ||||||
| 		InternalServiceInfoVec services; |         typedef std::vector<UserInfo>   UserInfoVec; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	struct SystemEndpoint { |         struct UserInfoList { | ||||||
| 		std::string type; |             std::vector<UserInfo>   users; | ||||||
| 		uint64_t 	id = 0; |  | ||||||
| 		std::string vendor{"OpenWiFi"}; |  | ||||||
| 		std::string uri; |  | ||||||
| 		std::string authenticationType{"internal_v1"}; |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
| 	typedef std::vector<SystemEndpoint> SystemEndpointVec; |  | ||||||
|  |  | ||||||
| 	struct SystemEndpointList { |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		SystemEndpointVec	endpoints; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |         }; | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	struct UserInfoAndPolicy { |         // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||||
| 		WebToken	webtoken; |         bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||||
| 		UserInfo	userinfo; |         bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
| 	typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy>	UserInfoCache; |  | ||||||
|  |  | ||||||
| 	enum ResourceAccessType { |         struct InternalServiceInfo { | ||||||
| 		NONE, |             std::string privateURI; | ||||||
| 		READ, |             std::string publicURI; | ||||||
| 		MODIFY, |             std::string token; | ||||||
| 		DELETE, |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		CREATE, |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		TEST, |         }; | ||||||
| 		MOVE |         typedef std::vector<InternalServiceInfo>	InternalServiceInfoVec; | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	ResourceAccessType ResourceAccessTypeFromString(const std::string &s); |         struct InternalSystemServices { | ||||||
| 	std::string ResourceAccessTypeToString(const ResourceAccessType & T); |             std::string key; | ||||||
|  |             std::string version; | ||||||
|  |             InternalServiceInfoVec services; | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
| 	struct ProfileAction { |         struct SystemEndpoint { | ||||||
| 		std::string resource; |             std::string type; | ||||||
| 		ResourceAccessType access; |             uint64_t 	id = 0; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |             std::string vendor{"OpenWiFi"}; | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); |             std::string uri; | ||||||
| 	}; |             std::string authenticationType{"internal_v1"}; | ||||||
| 	typedef std::vector<ProfileAction>	ProfileActionVec; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |         typedef std::vector<SystemEndpoint> SystemEndpointVec; | ||||||
|  |  | ||||||
| 	struct SecurityProfile { |         struct SystemEndpointList { | ||||||
| 		uint64_t id=0; |             SystemEndpointVec	endpoints; | ||||||
| 		std::string name; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		std::string description; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| 		ProfileActionVec policy; |         }; | ||||||
| 		std::string role; |  | ||||||
| 		NoteInfoVec notes; |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
| 	}; |  | ||||||
| 	typedef std::vector<SecurityProfile> SecurityProfileVec; |  | ||||||
|  |  | ||||||
| 	struct SecurityProfileList { |         struct UserInfoAndPolicy { | ||||||
| 		SecurityProfileVec profiles; |             WebToken	webtoken; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; |             UserInfo	userinfo; | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |         typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy>	UserInfoCache; | ||||||
|  |  | ||||||
| 	enum LinkActions { |         enum ResourceAccessType { | ||||||
| 	    FORGOT_PASSWORD=1, |             NONE, | ||||||
| 	    VERIFY_EMAIL |             READ, | ||||||
| 	}; |             MODIFY, | ||||||
|  |             DELETE, | ||||||
|  |             CREATE, | ||||||
|  |             TEST, | ||||||
|  |             MOVE | ||||||
|  |         }; | ||||||
|  |  | ||||||
| 	struct ActionLink { |         ResourceAccessType ResourceAccessTypeFromString(const std::string &s); | ||||||
| 	    std::string         id; |         std::string ResourceAccessTypeToString(const ResourceAccessType & T); | ||||||
| 	    uint64_t            action; |  | ||||||
| 	    std::string         userId; |  | ||||||
| 	    std::string         actionTemplate; |  | ||||||
| 	    Types::StringPairVec variables; |  | ||||||
| 	    std::string         locale; |  | ||||||
| 	    std::string         message; |  | ||||||
| 	    uint64_t            sent=0; |  | ||||||
| 	    uint64_t            created=std::time(nullptr); |  | ||||||
| 	    uint64_t            expires=0; |  | ||||||
| 	    uint64_t            completed=0; |  | ||||||
| 	    uint64_t            canceled=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         struct ProfileAction { | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); |             std::string resource; | ||||||
| 	}; |             ResourceAccessType access; | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |         typedef std::vector<ProfileAction>	ProfileActionVec; | ||||||
|  |  | ||||||
|  |         struct SecurityProfile { | ||||||
|  |             uint64_t id=0; | ||||||
|  |             std::string name; | ||||||
|  |             std::string description; | ||||||
|  |             ProfileActionVec policy; | ||||||
|  |             std::string role; | ||||||
|  |             NoteInfoVec notes; | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             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(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         enum LinkActions { | ||||||
|  |             FORGOT_PASSWORD=1, | ||||||
|  |             VERIFY_EMAIL, | ||||||
|  |             SUB_FORGOT_PASSWORD, | ||||||
|  |             SUB_VERIFY_EMAIL, | ||||||
|  |             SUB_SIGNUP | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct ActionLink { | ||||||
|  |             std::string         id; | ||||||
|  |             uint64_t            action; | ||||||
|  |             std::string         userId; | ||||||
|  |             std::string         actionTemplate; | ||||||
|  |             Types::StringPairVec variables; | ||||||
|  |             std::string         locale; | ||||||
|  |             std::string         message; | ||||||
|  |             uint64_t            sent=0; | ||||||
|  |             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(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct Preferences { | ||||||
|  |             std::string                         id; | ||||||
|  |             uint64_t                            modified; | ||||||
|  |             Types::StringPairVec                data; | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct SubMfaConfig { | ||||||
|  |             std::string                         id; | ||||||
|  |             std::string                         type; | ||||||
|  |             std::string                         sms; | ||||||
|  |             std::string                         email; | ||||||
|  |  | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct Token { | ||||||
|  |             std::string         token; | ||||||
|  |             std::string         refreshToken; | ||||||
|  |             std::string         tokenType; | ||||||
|  |             std::string         userName; | ||||||
|  |             uint64_t            created=0; | ||||||
|  |             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(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct Avatar { | ||||||
|  |             std::string             id; | ||||||
|  |             std::string             type; | ||||||
|  |             uint64_t                created=0; | ||||||
|  |             std::string             name; | ||||||
|  |             Poco::Data::BLOB        avatar; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         struct LoginRecordInfo { | ||||||
|  |             std::string sessionId; | ||||||
|  |             std::string userId; | ||||||
|  |             std::string email; | ||||||
|  |             uint64_t    login=0; | ||||||
|  |             uint64_t    logout=0; | ||||||
|  |  | ||||||
|  |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //UCENTRAL_RESTAPI_SECURITYOBJECTS_H |  | ||||||
							
								
								
									
										603
									
								
								src/RESTObjects/RESTAPI_SubObjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										603
									
								
								src/RESTObjects/RESTAPI_SubObjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,603 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-10-27. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "RESTAPI_SubObjects.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace OpenWifi::SubObjects { | ||||||
|  |  | ||||||
|  |     void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "enableLEDS", enableLEDS); | ||||||
|  |         field_to_json(Obj, "type", type); | ||||||
|  |         field_to_json(Obj, "subnet", subnet); | ||||||
|  |         field_to_json(Obj, "subnetMask", subnetMask); | ||||||
|  |         field_to_json(Obj, "startIP", startIP); | ||||||
|  |         field_to_json(Obj, "endIP", endIP); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |         field_to_json(Obj, "subnetV6", subnetV6); | ||||||
|  |         field_to_json(Obj, "subnetMaskV6", subnetMaskV6); | ||||||
|  |         field_to_json(Obj, "startIPV6", startIPV6); | ||||||
|  |         field_to_json(Obj, "endIPV6", endIPV6); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool HomeDeviceMode::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "enableLEDS", enableLEDS); | ||||||
|  |             field_from_json(Obj, "type", type); | ||||||
|  |             field_from_json(Obj, "subnet", subnet); | ||||||
|  |             field_from_json(Obj, "subnetMask", subnetMask); | ||||||
|  |             field_from_json(Obj, "startIP", startIP); | ||||||
|  |             field_from_json(Obj, "endIP", endIP); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             field_from_json(Obj, "subnetV6", subnetV6); | ||||||
|  |             field_from_json(Obj, "subnetMaskV6", subnetMaskV6); | ||||||
|  |             field_from_json(Obj, "startIPV6", startIPV6); | ||||||
|  |             field_from_json(Obj, "endIPV6", endIPV6); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void IPReservation::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "nickname", nickname); | ||||||
|  |         field_to_json(Obj, "ipAddress", ipAddress); | ||||||
|  |         field_to_json(Obj, "macAddress", macAddress); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool IPReservation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "nickname", nickname); | ||||||
|  |             field_from_json(Obj, "ipAddress", ipAddress); | ||||||
|  |             field_from_json(Obj, "macAddress", macAddress); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void IPReservationList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "id", id); | ||||||
|  |         field_to_json(Obj, "reservations", reservations); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool IPReservationList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "id", id); | ||||||
|  |             field_from_json(Obj, "reservations", reservations); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void DnsConfiguration::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "ISP", ISP); | ||||||
|  |         field_to_json(Obj, "custom", custom); | ||||||
|  |         field_to_json(Obj, "primary", primary); | ||||||
|  |         field_to_json(Obj, "secondary", secondary); | ||||||
|  |         field_to_json(Obj, "primaryV6", primaryV6); | ||||||
|  |         field_to_json(Obj, "secondaryV6", secondaryV6); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool DnsConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "ISP", ISP); | ||||||
|  |             field_from_json(Obj, "custom", custom); | ||||||
|  |             field_from_json(Obj, "primary", primary); | ||||||
|  |             field_from_json(Obj, "secondary", secondary); | ||||||
|  |             field_from_json(Obj, "primaryV6", primaryV6); | ||||||
|  |             field_from_json(Obj, "secondaryV6", secondaryV6); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void InternetConnection::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "type", type); | ||||||
|  |         field_to_json(Obj, "username", username); | ||||||
|  |         field_to_json(Obj, "password", password); | ||||||
|  |         field_to_json(Obj, "ipAddress", ipAddress); | ||||||
|  |         field_to_json(Obj, "subnetMask", subnetMask); | ||||||
|  |         field_to_json(Obj, "defaultGateway", defaultGateway); | ||||||
|  |         field_to_json(Obj, "sendHostname", sendHostname); | ||||||
|  |         field_to_json(Obj, "primaryDns", primaryDns); | ||||||
|  |         field_to_json(Obj, "secondaryDns", secondaryDns); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |         field_to_json(Obj, "ipV6Support", ipV6Support); | ||||||
|  |         field_to_json(Obj, "ipAddressV6", ipAddressV6); | ||||||
|  |         field_to_json(Obj, "subnetMaskV6", subnetMaskV6); | ||||||
|  |         field_to_json(Obj, "defaultGatewayV6", defaultGatewayV6); | ||||||
|  |         field_to_json(Obj, "primaryDnsV6", primaryDnsV6); | ||||||
|  |         field_to_json(Obj, "secondaryDnsV6", secondaryDnsV6); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool InternetConnection::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "type", type); | ||||||
|  |             field_from_json(Obj, "username", username); | ||||||
|  |             field_from_json(Obj, "password", password); | ||||||
|  |             field_from_json(Obj, "ipAddress", ipAddress); | ||||||
|  |             field_from_json(Obj, "subnetMask", subnetMask); | ||||||
|  |             field_from_json(Obj, "defaultGateway", defaultGateway); | ||||||
|  |             field_from_json(Obj, "sendHostname", sendHostname); | ||||||
|  |             field_from_json(Obj, "primaryDns", primaryDns); | ||||||
|  |             field_from_json(Obj, "secondaryDns", secondaryDns); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             field_from_json(Obj, "ipV6Support", ipV6Support); | ||||||
|  |             field_from_json(Obj, "ipAddressV6", ipAddressV6); | ||||||
|  |             field_from_json(Obj, "subnetMaskV6", subnetMaskV6); | ||||||
|  |             field_from_json(Obj, "defaultGatewayV6", defaultGatewayV6); | ||||||
|  |             field_from_json(Obj, "primaryDnsV6", primaryDnsV6); | ||||||
|  |             field_from_json(Obj, "secondaryDnsV6", secondaryDnsV6); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void WifiNetwork::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "type", type); | ||||||
|  |         field_to_json(Obj, "name", name); | ||||||
|  |         field_to_json(Obj, "password", password); | ||||||
|  |         field_to_json(Obj, "encryption", encryption); | ||||||
|  |         field_to_json(Obj, "bands", bands); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WifiNetwork::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "type", type); | ||||||
|  |             field_from_json(Obj, "name", name); | ||||||
|  |             field_from_json(Obj, "password", password); | ||||||
|  |             field_from_json(Obj, "encryption", encryption); | ||||||
|  |             field_from_json(Obj, "bands", bands); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void WifiNetworkList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "wifiNetworks", wifiNetworks); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool WifiNetworkList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "wifiNetworks", wifiNetworks); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AccessTime::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "day", day); | ||||||
|  |         field_to_json(Obj, "rangeList", rangeList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AccessTime::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "day", day); | ||||||
|  |             field_from_json(Obj, "rangeList", rangeList); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AccessTimes::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "schedule", schedule); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AccessTimes::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "schedule", schedule); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "name", name); | ||||||
|  |         field_to_json(Obj, "description", description); | ||||||
|  |         field_to_json(Obj, "macAddress", macAddress); | ||||||
|  |         field_to_json(Obj, "manufacturer", manufacturer); | ||||||
|  |         field_to_json(Obj, "firstContact", firstContact); | ||||||
|  |         field_to_json(Obj, "lastContact", lastContact); | ||||||
|  |         field_to_json(Obj, "group", group); | ||||||
|  |         field_to_json(Obj, "icon", icon); | ||||||
|  |         field_to_json(Obj, "suspended", suspended); | ||||||
|  |         field_to_json(Obj, "ip", ip); | ||||||
|  |         field_to_json(Obj, "schedule", schedule); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SubscriberDevice::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, "macAddress", macAddress); | ||||||
|  |             field_from_json(Obj, "manufacturer", manufacturer); | ||||||
|  |             field_from_json(Obj, "firstContact", firstContact); | ||||||
|  |             field_from_json(Obj, "lastContact", lastContact); | ||||||
|  |             field_from_json(Obj, "group", group); | ||||||
|  |             field_from_json(Obj, "icon", icon); | ||||||
|  |             field_from_json(Obj, "suspended", suspended); | ||||||
|  |             field_from_json(Obj, "ip", ip); | ||||||
|  |             field_from_json(Obj, "schedule", schedule); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "devices", devices); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "devices", devices); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Association::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "name", name); | ||||||
|  |         field_to_json(Obj, "ssid", ssid); | ||||||
|  |         field_to_json(Obj, "macAddress", macAddress); | ||||||
|  |         field_to_json(Obj, "rssi", rssi); | ||||||
|  |         field_to_json(Obj, "power", power); | ||||||
|  |         field_to_json(Obj, "ipv4", ipv4); | ||||||
|  |         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) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "name", name); | ||||||
|  |             field_from_json(Obj, "ssid", ssid); | ||||||
|  |             field_from_json(Obj, "macAddress", macAddress); | ||||||
|  |             field_from_json(Obj, "rssi", rssi); | ||||||
|  |             field_from_json(Obj, "power", power); | ||||||
|  |             field_from_json(Obj, "ipv4", ipv4); | ||||||
|  |             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 (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AssociationList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "associations", associations); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AssociationList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "associations", associations); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Client::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "macAddress", macAddress); | ||||||
|  |         field_to_json(Obj, "speed", speed); | ||||||
|  |         field_to_json(Obj, "mode", mode); | ||||||
|  |         field_to_json(Obj, "ipv4", ipv4); | ||||||
|  |         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) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "macAddress", macAddress); | ||||||
|  |             field_from_json(Obj, "speed", speed); | ||||||
|  |             field_from_json(Obj, "mode", mode); | ||||||
|  |             field_from_json(Obj, "ipv4", ipv4); | ||||||
|  |             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 (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void ClientList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "clients", clients); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool ClientList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "clients", clients); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Location::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             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); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RadioHE::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "multipleBSSID", multipleBSSID); | ||||||
|  |         field_to_json(Obj, "ema", ema); | ||||||
|  |         field_to_json(Obj, "bssColor", bssColor); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool RadioHE::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "multipleBSSID", multipleBSSID); | ||||||
|  |             field_from_json(Obj, "ema", ema); | ||||||
|  |             field_from_json(Obj, "bssColor", bssColor); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RadioRates::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "beacon", beacon); | ||||||
|  |         field_to_json(Obj, "multicast", multicast); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool RadioRates::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "beacon", beacon); | ||||||
|  |             field_from_json(Obj, "multicast", multicast); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RadioInformation::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "band", band); | ||||||
|  |         field_to_json(Obj, "bandwidth", bandwidth); | ||||||
|  |         field_to_json(Obj, "channel", channel); | ||||||
|  |         field_to_json(Obj, "country", country); | ||||||
|  |         field_to_json(Obj, "channelMode", channelMode); | ||||||
|  |         field_to_json(Obj, "channelWidth", channelWidth); | ||||||
|  |         field_to_json(Obj, "requireMode", requireMode); | ||||||
|  |         field_to_json(Obj, "txpower", txpower); | ||||||
|  |         field_to_json(Obj, "legacyRates", legacyRates); | ||||||
|  |         field_to_json(Obj, "beaconInterval", beaconInterval); | ||||||
|  |         field_to_json(Obj, "dtimPeriod", dtimPeriod); | ||||||
|  |         field_to_json(Obj, "maximumClients", maximumClients); | ||||||
|  |         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) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "band", band); | ||||||
|  |             field_from_json(Obj, "bandwidth", bandwidth); | ||||||
|  |             field_from_json(Obj, "channel", channel); | ||||||
|  |             field_from_json(Obj, "country", country); | ||||||
|  |             field_from_json(Obj, "channelMode", channelMode); | ||||||
|  |             field_from_json(Obj, "channelWidth", channelWidth); | ||||||
|  |             field_from_json(Obj, "requireMode", requireMode); | ||||||
|  |             field_from_json(Obj, "txpower", txpower); | ||||||
|  |             field_from_json(Obj, "legacyRates", legacyRates); | ||||||
|  |             field_from_json(Obj, "beaconInterval", beaconInterval); | ||||||
|  |             field_from_json(Obj, "dtimPeriod", dtimPeriod); | ||||||
|  |             field_from_json(Obj, "maximumClients", maximumClients); | ||||||
|  |             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 (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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); | ||||||
|  |         field_to_json(Obj, "ipReservations", ipReservations); | ||||||
|  |         field_to_json(Obj, "address", address); | ||||||
|  |         field_to_json(Obj, "wifiNetworks", wifiNetworks); | ||||||
|  |         field_to_json(Obj, "internetConnection", internetConnection); | ||||||
|  |         field_to_json(Obj, "deviceMode", deviceMode); | ||||||
|  |         field_to_json(Obj, "dnsConfiguration", dnsConfiguration); | ||||||
|  |         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); | ||||||
|  |             field_from_json(Obj, "ipReservations", ipReservations); | ||||||
|  |             field_from_json(Obj, "address", address); | ||||||
|  |             field_from_json(Obj, "wifiNetworks", wifiNetworks); | ||||||
|  |             field_from_json(Obj, "internetConnection", internetConnection); | ||||||
|  |             field_from_json(Obj, "deviceMode", deviceMode); | ||||||
|  |             field_from_json(Obj, "dnsConfiguration", dnsConfiguration); | ||||||
|  |             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 (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AccessPointList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "list", list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AccessPointList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "list", list); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SubscriberInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "id", id); | ||||||
|  |         field_to_json(Obj, "userId", userId); | ||||||
|  |         field_to_json(Obj, "firstName", firstName); | ||||||
|  |         field_to_json(Obj, "initials", initials); | ||||||
|  |         field_to_json(Obj, "lastName", lastName); | ||||||
|  |         field_to_json(Obj, "phoneNumber", phoneNumber); | ||||||
|  |         field_to_json(Obj, "secondaryEmail", secondaryEmail); | ||||||
|  |         field_to_json(Obj, "accessPoints", accessPoints); | ||||||
|  |         field_to_json(Obj, "serviceAddress", serviceAddress); | ||||||
|  |         field_to_json(Obj, "billingAddress", billingAddress); | ||||||
|  |         field_to_json(Obj, "created", created); | ||||||
|  |         field_to_json(Obj, "modified", modified); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SubscriberInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "id", id); | ||||||
|  |             field_from_json(Obj, "userId", userId); | ||||||
|  |             field_from_json(Obj, "firstName", firstName); | ||||||
|  |             field_from_json(Obj, "initials", initials); | ||||||
|  |             field_from_json(Obj, "lastName", lastName); | ||||||
|  |             field_from_json(Obj, "phoneNumber", phoneNumber); | ||||||
|  |             field_from_json(Obj, "secondaryEmail", secondaryEmail); | ||||||
|  |             field_from_json(Obj, "accessPoints", accessPoints); | ||||||
|  |             field_from_json(Obj, "serviceAddress", serviceAddress); | ||||||
|  |             field_from_json(Obj, "billingAddress", billingAddress); | ||||||
|  |             field_from_json(Obj, "created", created); | ||||||
|  |             field_from_json(Obj, "modified", modified); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |         } | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										322
									
								
								src/RESTObjects/RESTAPI_SubObjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								src/RESTObjects/RESTAPI_SubObjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,322 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-10-27. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef OWSUB_RESTAPI_SUBOBJECTS_H | ||||||
|  | #define OWSUB_RESTAPI_SUBOBJECTS_H | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | #include "Poco/JSON/Object.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi::SubObjects { | ||||||
|  |  | ||||||
|  |     struct HomeDeviceMode { | ||||||
|  |         bool            enableLEDS = true; | ||||||
|  |         std::string     type;       // bridge, manual, automatic | ||||||
|  |         std::string     subnet; | ||||||
|  |         std::string     subnetMask; | ||||||
|  |         std::string     startIP; | ||||||
|  |         std::string     endIP; | ||||||
|  |         uint64_t        created = 0 ; | ||||||
|  |         uint64_t        modified = 0 ; | ||||||
|  |         std::string     subnetV6; | ||||||
|  |         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); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct IPReservation  { | ||||||
|  |         std::string     nickname; | ||||||
|  |         std::string     ipAddress; | ||||||
|  |         std::string     macAddress; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct IPReservationList { | ||||||
|  |         std::string                 id; | ||||||
|  |         std::vector<IPReservation>  reservations; | ||||||
|  |         uint64_t created = 0 ; | ||||||
|  |         uint64_t modified = 0 ; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct DnsConfiguration { | ||||||
|  |         bool            ISP=false; | ||||||
|  |         bool            custom=false; | ||||||
|  |         std::string     primary; | ||||||
|  |         std::string     secondary; | ||||||
|  |         std::string     primaryV6; | ||||||
|  |         std::string     secondaryV6; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct InternetConnection { | ||||||
|  |         std::string     type; // automatic, pppoe, manual | ||||||
|  |         std::string     username; | ||||||
|  |         std::string     password; | ||||||
|  |         std::string     ipAddress; | ||||||
|  |         std::string     subnetMask; | ||||||
|  |         std::string     defaultGateway; | ||||||
|  |         bool            sendHostname = true; | ||||||
|  |         std::string     primaryDns; | ||||||
|  |         std::string     secondaryDns; | ||||||
|  |         uint64_t        created=0; | ||||||
|  |         uint64_t        modified=0; | ||||||
|  |         bool            ipV6Support=false; | ||||||
|  |         std::string     ipAddressV6; | ||||||
|  |         int             subnetMaskV6=0; | ||||||
|  |         std::string     defaultGatewayV6; | ||||||
|  |         std::string     primaryDnsV6; | ||||||
|  |         std::string     secondaryDnsV6; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct WifiNetwork { | ||||||
|  |         std::string     type;       // main, guest | ||||||
|  |         std::string     name; | ||||||
|  |         std::string     password; | ||||||
|  |         std::string     encryption; | ||||||
|  |         std::vector<std::string>    bands; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct WifiNetworkList { | ||||||
|  |         std::vector<WifiNetwork>    wifiNetworks; | ||||||
|  |         uint64_t                    created=0; | ||||||
|  |         uint64_t                    modified=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct AccessTime { | ||||||
|  |         std::string day; | ||||||
|  |         std::vector<std::string>    rangeList; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct AccessTimes { | ||||||
|  |         std::vector<AccessTime> schedule; | ||||||
|  |         uint64_t        created=0; | ||||||
|  |         uint64_t        modified=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SubscriberDevice { | ||||||
|  |         std::string     name; | ||||||
|  |         std::string     description; | ||||||
|  |         std::string     macAddress; | ||||||
|  |         std::string     manufacturer; | ||||||
|  |         uint64_t        firstContact=0; | ||||||
|  |         uint64_t        lastContact=0; | ||||||
|  |         std::string     group; | ||||||
|  |         std::string     icon; | ||||||
|  |         bool            suspended=false; | ||||||
|  |         std::string     ip; | ||||||
|  |         std::vector<AccessTimes>    schedule; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SubscriberDeviceList { | ||||||
|  |         std::vector<SubscriberDevice>   devices; | ||||||
|  |         uint64_t        created=0; | ||||||
|  |         uint64_t        modified=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct Association { | ||||||
|  |         std::string     name; | ||||||
|  |         std::string     ssid; | ||||||
|  |         std::string     macAddress; | ||||||
|  |         int             rssi=0; | ||||||
|  |         int             power=0; | ||||||
|  |         std::string     ipv4; | ||||||
|  |         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); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct AssociationList { | ||||||
|  |         std::vector<Association>    associations; | ||||||
|  |         uint64_t        created=0; | ||||||
|  |         uint64_t        modified=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct Client { | ||||||
|  |         std::string     macAddress; | ||||||
|  |         std::string     speed; | ||||||
|  |         std::string     mode; | ||||||
|  |         std::string     ipv4; | ||||||
|  |         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); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct ClientList { | ||||||
|  |         std::vector<Client> clients; | ||||||
|  |         uint64_t        created=0; | ||||||
|  |         uint64_t        modified=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct Location { | ||||||
|  |         std::string                 buildingName; | ||||||
|  |         std::vector<std::string>    addressLines; | ||||||
|  |         std::string                 city; | ||||||
|  |         std::string                 state; | ||||||
|  |         std::string                 postal; | ||||||
|  |         std::string                 country; | ||||||
|  |         std::vector<std::string>    phones; | ||||||
|  |         std::vector<std::string>    mobiles; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct RadioHE { | ||||||
|  |         bool                        multipleBSSID = false; | ||||||
|  |         bool                        ema = false; | ||||||
|  |         uint64_t                    bssColor = 64; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct RadioRates { | ||||||
|  |         uint64_t                    beacon = 6000; | ||||||
|  |         uint64_t                    multicast = 24000; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct RadioInformation { | ||||||
|  |         std::string             band; | ||||||
|  |         uint64_t                bandwidth; | ||||||
|  |         uint64_t                channel = 0 ; | ||||||
|  |         std::string             country; | ||||||
|  |         std::string             channelMode{"HE"}; | ||||||
|  |         uint64_t                channelWidth = 80; | ||||||
|  |         std::string             requireMode; | ||||||
|  |         uint64_t                txpower=0; | ||||||
|  |         bool                    legacyRates = false; | ||||||
|  |         uint64_t                beaconInterval = 100; | ||||||
|  |         uint64_t                dtimPeriod = 2; | ||||||
|  |         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; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct AccessPoint { | ||||||
|  |         std::string                 id; | ||||||
|  |         std::string                 macAddress; | ||||||
|  |         std::string                 serialNumber; | ||||||
|  |         std::string                 name; | ||||||
|  |         std::string                 deviceType; | ||||||
|  |         SubscriberDeviceList        subscriberDevices; | ||||||
|  |         IPReservationList           ipReservations; | ||||||
|  |         Location                    address; | ||||||
|  |         WifiNetworkList             wifiNetworks; | ||||||
|  |         InternetConnection          internetConnection; | ||||||
|  |         HomeDeviceMode              deviceMode; | ||||||
|  |         DnsConfiguration            dnsConfiguration; | ||||||
|  |         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); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct AccessPointList { | ||||||
|  |         std::vector<AccessPoint>   list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SubscriberInfo { | ||||||
|  |         std::string                 id; | ||||||
|  |         std::string                 userId; | ||||||
|  |         std::string                 firstName; | ||||||
|  |         std::string                 initials; | ||||||
|  |         std::string                 lastName; | ||||||
|  |         std::string                 phoneNumber; | ||||||
|  |         std::string                 secondaryEmail; | ||||||
|  |         AccessPointList             accessPoints; | ||||||
|  |         Location                    serviceAddress; | ||||||
|  |         Location                    billingAddress; | ||||||
|  |         uint64_t                    created = 0; | ||||||
|  |         uint64_t                    modified = 0; | ||||||
|  |  | ||||||
|  |         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 | ||||||
| @@ -20,12 +20,13 @@ namespace OpenWifi { | |||||||
|         if(Enabled_) { |         if(Enabled_) { | ||||||
|             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); |             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); | ||||||
|             if(Provider_=="aws") { |             if(Provider_=="aws") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); |                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger()); | ||||||
|             } else if(Provider_=="twilio") { |             } else if(Provider_=="twilio") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); |                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger()); | ||||||
|             } |             } | ||||||
|             Enabled_ = ProviderImpl_->Initialize(); |             Enabled_ = ProviderImpl_->Initialize(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -33,7 +34,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void SMSSender::CleanCache() { |     void SMSSender::CleanCache() { | ||||||
|         uint64_t Now=std::time(nullptr); |         uint64_t Now=OpenWifi::Now(); | ||||||
|         for(auto i=begin(Cache_);i!=end(Cache_);) { |         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||||
|             if((Now-i->Created)>300) |             if((Now-i->Created)>300) | ||||||
|                 i = Cache_.erase(i); |                 i = Cache_.erase(i); | ||||||
| @@ -44,8 +45,10 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { |     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|         CleanCache(); |         CleanCache(); | ||||||
|         uint64_t Now=std::time(nullptr); |         uint64_t Now=OpenWifi::Now(); | ||||||
|         auto Challenge = MFAServer::MakeChallenge(); |         auto Challenge = MFAServer::MakeChallenge(); | ||||||
|         Cache_.emplace_back(SMSValidationCacheEntry{.Number=Number, .Code=Challenge, .UserName=UserName, .Created=Now}); |         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; |         std::string Message = "Please enter the following code on your login screen: " + Challenge; | ||||||
| @@ -55,6 +58,9 @@ namespace OpenWifi { | |||||||
|     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { |     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |  | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|         for(const auto &i:Cache_) { |         for(const auto &i:Cache_) { | ||||||
|             if(i.Number==Number && i.UserName==UserName) |             if(i.Number==Number && i.UserName==UserName) | ||||||
|                 return i.Validated; |                 return i.Validated; | ||||||
| @@ -65,6 +71,9 @@ namespace OpenWifi { | |||||||
|     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { |     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |  | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|         for(auto &i:Cache_) { |         for(auto &i:Cache_) { | ||||||
|             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { |             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { | ||||||
|                 i.Validated=true; |                 i.Validated=true; | ||||||
| @@ -76,7 +85,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { |     bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { | ||||||
|         if(!Enabled_) { |         if(!Enabled_) { | ||||||
|             Logger_.information("SMS has not been enabled. Messages cannot be sent."); |             Logger().information("SMS has not been enabled. Messages cannot be sent."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         return ProviderImpl_->Send(PhoneNumber,Message); |         return ProviderImpl_->Send(PhoneNumber,Message); | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | |||||||
|         std::string Number; |         std::string Number; | ||||||
|         std::string Code; |         std::string Code; | ||||||
|         std::string UserName; |         std::string UserName; | ||||||
|         uint64_t    Created = std::time(nullptr); |         uint64_t    Created = OpenWifi::Now(); | ||||||
|         bool        Validated = false; |         bool        Validated = false; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | |||||||
|         Region_ = MicroService::instance().ConfigGetString("smssender.aws.region",""); |         Region_ = MicroService::instance().ConfigGetString("smssender.aws.region",""); | ||||||
|  |  | ||||||
|         if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) { |         if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) { | ||||||
|             Logger_.debug("SMSSender is disabled. Please provide key, secret, and region."); |             Logger().debug("SMSSender is disabled. Please provide key, secret, and region."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         Running_=true; |         Running_=true; | ||||||
| @@ -51,16 +51,16 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             auto psms_out = sns.Publish(psms_req); |             auto psms_out = sns.Publish(psms_req); | ||||||
|             if (psms_out.IsSuccess()) { |             if (psms_out.IsSuccess()) { | ||||||
|                 Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber)); |                 Logger().debug(fmt::format("SMS sent to {}",PhoneNumber)); | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|             std::string ErrMsg{psms_out.GetError().GetMessage()}; |             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; |             return false; | ||||||
|         } catch (...) { |         } 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; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ namespace OpenWifi { | |||||||
|         bool Stop() final ; |         bool Stop() final ; | ||||||
|         bool Send(const std::string &Number, const std::string &Message) final; |         bool Send(const std::string &Number, const std::string &Message) final; | ||||||
|         bool Running() final; |         bool Running() final; | ||||||
|  |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     private: |     private: | ||||||
|         bool                                Running_=false; |         bool                                Running_=false; | ||||||
|         Poco::Logger                        &Logger_; |         Poco::Logger                        &Logger_; | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | |||||||
|         PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); |         PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); | ||||||
|  |  | ||||||
|         if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { |         if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { | ||||||
|             Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); |             Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         Running_=true; |         Running_=true; | ||||||
| @@ -52,9 +52,9 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         Poco::JSON::Object  RObj; |         Poco::JSON::Object  RObj; | ||||||
|  |  | ||||||
|         form.add("To",PhoneNumber); |         form.add("To", PhoneNumber); | ||||||
|         form.add("From",PhoneNumber_); |         form.add("From", PhoneNumber_); | ||||||
|         form.add("Body","This is from twillio"); |         form.add("Body", Message); | ||||||
|  |  | ||||||
|         form.prepareSubmit(req); |         form.prepareSubmit(req); | ||||||
|         std::ostream& ostr = session.sendRequest(req); |         std::ostream& ostr = session.sendRequest(req); | ||||||
| @@ -64,12 +64,12 @@ namespace OpenWifi { | |||||||
|         std::istream& rs = session.receiveResponse(res); |         std::istream& rs = session.receiveResponse(res); | ||||||
|  |  | ||||||
|         if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { |         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; |             return true; | ||||||
|         } else { |         } else { | ||||||
|             std::ostringstream os; |             std::ostringstream os; | ||||||
|             Poco::StreamCopier::copyStream(rs,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; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ namespace OpenWifi { | |||||||
|         bool Stop() final ; |         bool Stop() final ; | ||||||
|         bool Send(const std::string &Number, const std::string &Message) final; |         bool Send(const std::string &Number, const std::string &Message) final; | ||||||
|         bool Running() final; |         bool Running() final; | ||||||
|  |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     private: |     private: | ||||||
|         bool                                Running_=false; |         bool                                Running_=false; | ||||||
|         Poco::Logger                        &Logger_; |         Poco::Logger                        &Logger_; | ||||||
|   | |||||||
| @@ -27,10 +27,10 @@ namespace OpenWifi { | |||||||
|             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); |             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); | ||||||
|             Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); |             Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); | ||||||
|             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); |             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()); |             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); | ||||||
|             MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60); |             MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||||
|             MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); |             MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||||
|             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); |             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -47,15 +47,15 @@ namespace OpenWifi { | |||||||
|         SenderThr_.join(); |         SenderThr_.join(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void SMTPMailerService::reinitialize(Poco::Util::Application &self) { |     void SMTPMailerService::reinitialize([[maybe_unused]] Poco::Util::Application &self) { | ||||||
|         MicroService::instance().LoadConfigurationFile(); |         MicroService::instance().LoadConfigurationFile(); | ||||||
|         Logger_.information("Reinitializing."); |         Logger().information("Reinitializing."); | ||||||
|         LoadMyConfig(); |         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_); |         std::lock_guard G(Mutex_); | ||||||
|         PendingMessages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr), |         PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(), | ||||||
|                                             .LastTry=0, |                                             .LastTry=0, | ||||||
|                                             .Sent=0, |                                             .Sent=0, | ||||||
|                                             .File=Poco::File(TemplateDir_ + "/" +Name), |                                             .File=Poco::File(TemplateDir_ + "/" +Name), | ||||||
| @@ -65,6 +65,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void SMTPMailerService::run() { |     void SMTPMailerService::run() { | ||||||
|         Running_ = true; |         Running_ = true; | ||||||
|  |         Utils::SetThreadName("smtp-mailer"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|  |  | ||||||
|             Poco::Thread::trySleep(10000); |             Poco::Thread::trySleep(10000); | ||||||
| @@ -80,17 +81,17 @@ namespace OpenWifi { | |||||||
|                 if(!Running_) |                 if(!Running_) | ||||||
|                     break; |                     break; | ||||||
|                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; |                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; | ||||||
|                 uint64_t Now = std::time(nullptr); |                 uint64_t now = OpenWifi::Now(); | ||||||
|                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { |                 if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) { | ||||||
|                     if (SendIt(*i)) { |                     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); |                         i = Messages_.erase(i); | ||||||
|                     } else { |                     } else { | ||||||
|                         i->LastTry = Now; |                         i->LastTry = now; | ||||||
|                         ++i; |                         ++i; | ||||||
|                     } |                     } | ||||||
|                 } else if ((Now-i->Posted)>MailAbandon_) { |                 } else if ((now-i->Posted)>MailAbandon_) { | ||||||
|                     Logger_.information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient)); |                     Logger().information(fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient)); | ||||||
|                     i = Messages_.erase(i); |                     i = Messages_.erase(i); | ||||||
|                 } else { |                 } else { | ||||||
|                     ++i; |                     ++i; | ||||||
| @@ -121,7 +122,7 @@ namespace OpenWifi { | |||||||
|                 TheSender = Sender_ ; |                 TheSender = Sender_ ; | ||||||
|             } |             } | ||||||
|             Message.setSender( TheSender ); |             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.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); |             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||||
|  |  | ||||||
| @@ -130,9 +131,11 @@ namespace OpenWifi { | |||||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); |                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||||
|             } else { |             } else { | ||||||
|                 std::string Content = Utils::LoadFile(Msg.File); |                 std::string Content = Utils::LoadFile(Msg.File); | ||||||
|  |                 // std::cout << "Mailing " << Content << std::endl; | ||||||
|                 Types::StringPairVec    Variables; |                 Types::StringPairVec    Variables; | ||||||
|                 FillVariables(Msg.Attrs, Variables); |                 FillVariables(Msg.Attrs, Variables); | ||||||
|                 Utils::ReplaceVariables(Content, Variables); |                 Utils::ReplaceVariables(Content, Variables); | ||||||
|  |                 // std::cout << "Mailing " << Content << std::endl; | ||||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); |                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -145,7 +148,7 @@ namespace OpenWifi { | |||||||
|                     Poco::StreamCopier::copyStream(IF, OS); |                     Poco::StreamCopier::copyStream(IF, OS); | ||||||
|                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); |                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||||
|                 } catch (...) { |                 } catch (...) { | ||||||
|                     Logger_.warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); |                     Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName())); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -172,10 +175,10 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|         catch (const Poco::Exception& E) |         catch (const Poco::Exception& E) | ||||||
|         { |         { | ||||||
|             Logger_.log(E); |             Logger().log(E); | ||||||
|         } |         } | ||||||
|         catch (const std::exception &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; |         return false; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -84,9 +84,9 @@ namespace OpenWifi { | |||||||
|         private: |         private: | ||||||
|             std::string             MailHost_; |             std::string             MailHost_; | ||||||
|             std::string             Sender_; |             std::string             Sender_; | ||||||
|             int                     MailHostPort_=25; |             uint32_t                MailHostPort_=25; | ||||||
|             int                     MailRetry_=2*60; |             uint64_t                MailRetry_=2*60; | ||||||
|             int                     MailAbandon_=2*60*20; |             uint64_t                MailAbandon_=2*60*20; | ||||||
|             std::string             SenderLoginUserName_; |             std::string             SenderLoginUserName_; | ||||||
|             std::string             SenderLoginPassword_; |             std::string             SenderLoginPassword_; | ||||||
|             std::string             LoginMethod_ = "login"; |             std::string             LoginMethod_ = "login"; | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								src/SpecialUserHelpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/SpecialUserHelpers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-28. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "StorageService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     namespace SpecialUserHelpers { | ||||||
|  |         static inline std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"}; | ||||||
|  |  | ||||||
|  |         inline bool InitializeDefaultUser() { | ||||||
|  |             SecurityObjects::UserInfo U; | ||||||
|  |             bool DefaultUserCreated = false; | ||||||
|  |  | ||||||
|  |             AppServiceRegistry().Get("defaultusercreated", DefaultUserCreated); | ||||||
|  |             if (!StorageService()->UserDB().GetUserById(NewDefaultUseridStockUUID, U) && !DefaultUserCreated) { | ||||||
|  |                 U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password", ""); | ||||||
|  |                 U.lastPasswords.push_back(U.currentPassword); | ||||||
|  |                 U.email = MicroService::instance().ConfigGetString("authentication.default.username", ""); | ||||||
|  |                 U.id = NewDefaultUseridStockUUID; | ||||||
|  |                 U.userRole = SecurityObjects::ROOT; | ||||||
|  |                 U.creationDate = OpenWifi::Now(); | ||||||
|  |                 U.validated = true; | ||||||
|  |                 U.name = "Default User"; | ||||||
|  |                 U.description = "Default user should be deleted."; | ||||||
|  |                 U.changePassword = true; | ||||||
|  |                 StorageService()->UserDB().CreateUser("SYSTEM", U, true); | ||||||
|  |                 AppServiceRegistry().Set("defaultusercreated", true); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -7,15 +7,46 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
|  | #include "SpecialUserHelpers.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     int Storage::Start() { |     int StorageService::Start() { | ||||||
| 		std::lock_guard		Guard(Mutex_); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
| 		StorageClass::Start(); | 		StorageClass::Start(); | ||||||
| 		Create_Tables(); |  | ||||||
| 		InitializeDefaultUser(); |         UserCache_ = std::make_unique<OpenWifi::UserCache>(64,1200000,true); | ||||||
|  |         SubCache_ = std::make_unique<OpenWifi::UserCache>(2048,1200000,false); | ||||||
|  |         UserTokenCache_ = std::make_unique<OpenWifi::TokenCache>(64,1200000, true); | ||||||
|  |         SubTokenCache_ = std::make_unique<OpenWifi::TokenCache>(2048,1200000,false); | ||||||
|  |  | ||||||
|  |         UserDB_ = std::make_unique<OpenWifi::BaseUserDB>("Users", "usr", dbType_,*Pool_, Logger(), UserCache_.get(), true); | ||||||
|  |         SubDB_ = std::make_unique<OpenWifi::BaseUserDB>("Subscribers", "sub", dbType_,*Pool_, Logger(), SubCache_.get(), false); | ||||||
|  |         UserTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("Tokens", "tok", dbType_,*Pool_, Logger(), UserTokenCache_.get(), true); | ||||||
|  |         SubTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("SubTokens", "stk", dbType_,*Pool_, Logger(), SubTokenCache_.get(), false); | ||||||
|  |  | ||||||
|  |         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>("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()); | ||||||
|  |  | ||||||
|  |         UserDB_->Create(); | ||||||
|  |         SubDB_->Create(); | ||||||
|  |         UserTokenDB_->Create(); | ||||||
|  |         SubTokenDB_->Create(); | ||||||
|  |         ActionLinksDB_->Create(); | ||||||
|  |         PreferencesDB_->Create(); | ||||||
|  |         SubPreferencesDB_->Create(); | ||||||
|  |         AvatarDB_->Create(); | ||||||
|  |         SubAvatarDB_->Create(); | ||||||
|  |         LoginDB_->Create(); | ||||||
|  |         SubLoginDB_->Create(); | ||||||
|  |  | ||||||
|  | 		OpenWifi::SpecialUserHelpers::InitializeDefaultUser(); | ||||||
|  |  | ||||||
| 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | ||||||
| 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | ||||||
| @@ -25,18 +56,20 @@ namespace OpenWifi { | |||||||
| 		return 0; | 		return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Storage::Stop() { |     void StorageService::Stop() { | ||||||
|         Logger_.notice("Stopping."); |         Logger().notice("Stopping."); | ||||||
|         Timer_.stop(); |         Timer_.stop(); | ||||||
|         StorageClass::Stop(); |         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"); |         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); | ||||||
|         logger.information("Squiggy the DB: removing old tokens."); |         logger.information("Squiggy the DB: removing old tokens."); | ||||||
|         StorageService()->CleanExpiredTokens(); |         StorageService()->SubTokenDB().CleanExpiredTokens(); | ||||||
|  |         StorageService()->UserTokenDB().CleanExpiredTokens(); | ||||||
|         logger.information("Squiggy the DB: removing old actionLinks."); |         logger.information("Squiggy the DB: removing old actionLinks."); | ||||||
|         StorageService()->CleanOldActionLinks(); |         StorageService()->ActionLinksDB().CleanOldActionLinks(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,138 +15,69 @@ | |||||||
|  |  | ||||||
| #include "Poco/Timer.h" | #include "Poco/Timer.h" | ||||||
|  |  | ||||||
|  | #include "storage/orm_users.h" | ||||||
|  | #include "storage/orm_tokens.h" | ||||||
|  | #include "storage/orm_preferences.h" | ||||||
|  | #include "storage/orm_actionLinks.h" | ||||||
|  | #include "storage/orm_avatar.h" | ||||||
|  | #include "storage/orm_logins.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static const std::string AllEmailTemplatesFieldsForCreation { |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static const std::string AllEmailTemplatesFieldsForSelect { |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static const std::string AllEmailTemplatesFieldsForUpdate { |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class Archiver { |     class Archiver { | ||||||
|     public: |     public: | ||||||
|         void onTimer(Poco::Timer & timer); |         void onTimer(Poco::Timer & timer); | ||||||
|     private: |     private: | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class Storage : public StorageClass { |     class StorageService : public StorageClass { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|         enum AUTH_ERROR { |         static auto instance() { | ||||||
|             SUCCESS, |             static auto instance_ = new StorageService; | ||||||
|             PASSWORD_CHANGE_REQUIRED, |  | ||||||
|             PASSWORD_DOES_NOT_MATCH, |  | ||||||
|             PASSWORD_ALREADY_USED, |  | ||||||
|             USERNAME_PENDING_VERIFICATION, |  | ||||||
|             PASSWORD_INVALID, |  | ||||||
|             INTERNAL_ERROR |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         enum USER_TYPE { |  | ||||||
|             UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, SPECIAL |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         typedef std::string USER_ID_TYPE; |  | ||||||
|  |  | ||||||
|         static USER_TYPE to_userType(const std::string &U) { |  | ||||||
|             if (U=="root") |  | ||||||
|                 return ROOT; |  | ||||||
|             else if (U=="admin") |  | ||||||
|                 return ADMIN; |  | ||||||
|             else if (U=="subscriber") |  | ||||||
|                 return SUBSCRIBER; |  | ||||||
|             else if (U=="csr") |  | ||||||
|                 return CSR; |  | ||||||
|             else if (U=="system") |  | ||||||
|                 return SYSTEM; |  | ||||||
|             else if (U=="SPECIAL") |  | ||||||
|                 return SPECIAL; |  | ||||||
|             return UNKNOWN; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         static std::string from_userType(USER_TYPE U) { |  | ||||||
|             switch(U) { |  | ||||||
|                 case ROOT: return "root"; |  | ||||||
|                 case ADMIN: return "admin"; |  | ||||||
|                 case SUBSCRIBER: return "subscriber"; |  | ||||||
|                 case CSR: return "csr"; |  | ||||||
|                 case SYSTEM: return "system"; |  | ||||||
|                 case SPECIAL: return "special"; |  | ||||||
|                 case UNKNOWN: |  | ||||||
|                 default: return "unknown"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         static Storage *instance() { |  | ||||||
|             static auto * instance_ = new Storage; |  | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int 	Start() override; |         int 	Start() override; | ||||||
|         void 	Stop() override; |         void 	Stop() override; | ||||||
|  |  | ||||||
|         /* |         OpenWifi::BaseUserDB & UserDB() { return *UserDB_; } | ||||||
|          *  All user management functions |         OpenWifi::BaseUserDB & SubDB() { return *SubDB_; } | ||||||
|          */ |         OpenWifi::BaseTokenDB & UserTokenDB() { return *UserTokenDB_; } | ||||||
|         bool InitializeDefaultUser(); |         OpenWifi::BaseTokenDB & SubTokenDB() { return *SubTokenDB_; } | ||||||
|         bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false); |         OpenWifi::PreferencesDB & PreferencesDB() { return *PreferencesDB_; } | ||||||
|         bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); |         OpenWifi::PreferencesDB & SubPreferencesDB() { return *SubPreferencesDB_; } | ||||||
|         bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); |         OpenWifi::ActionLinkDB & ActionLinksDB() { return *ActionLinksDB_; } | ||||||
|         bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); |         OpenWifi::AvatarDB & AvatarDB() { return *AvatarDB_; } | ||||||
|         bool SetOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner); |         OpenWifi::AvatarDB & SubAvatarDB() { return *SubAvatarDB_; } | ||||||
|         bool SetLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location); |         OpenWifi::LoginDB & LoginDB() { return *LoginDB_; } | ||||||
|         AUTH_ERROR ChangePassword(const std::string & Admin, USER_ID_TYPE & Id, const std::string &OldPassword, const std::string &NewPassword); |         OpenWifi::LoginDB & SubLoginDB() { return *SubLoginDB_; } | ||||||
|         bool AddNotes(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Notes); |  | ||||||
|         bool SetPolicyChange(const std::string & Admin, USER_ID_TYPE & Id, const std::string &NewPolicy); |  | ||||||
|         bool UpdateUserInfo(const std::string & Admin, USER_ID_TYPE & Id, SecurityObjects::UserInfo &UInfo); |  | ||||||
|         bool GetUsers( uint64_t Offset, uint64_t Limit, SecurityObjects::UserInfoVec & Users); |  | ||||||
|         bool SetLastLogin(USER_ID_TYPE & Id); |  | ||||||
|  |  | ||||||
|         bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); |  | ||||||
|         bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); |  | ||||||
|         bool DeleteAvatar(const std::string & Admin, std::string &Id); |  | ||||||
|  |  | ||||||
|         bool AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut); |  | ||||||
|         bool RevokeToken( std::string & Token ); |  | ||||||
|         bool IsTokenRevoked( std::string & Token ); |  | ||||||
|         bool CleanExpiredTokens(); |  | ||||||
|         bool RevokeAllTokens( std::string & UserName ); |  | ||||||
|         bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate); |  | ||||||
|  |  | ||||||
|         /* |  | ||||||
|          *  All ActionLinks functions |  | ||||||
|          */ |  | ||||||
|         bool CreateAction( SecurityObjects::ActionLink & A); |  | ||||||
|         bool DeleteAction(std::string &ActionId); |  | ||||||
|         bool CompleteAction(std::string &ActionId); |  | ||||||
|         bool CancelAction(std::string &ActionId); |  | ||||||
|         bool SentAction(std::string &ActionId); |  | ||||||
|         bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); |  | ||||||
|         bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); |  | ||||||
|         void CleanOldActionLinks(); |  | ||||||
|  |  | ||||||
| 	  private: | 	  private: | ||||||
|         int Create_Tables(); |  | ||||||
|         int Create_UserTable(); |         std::unique_ptr<OpenWifi::BaseUserDB>           UserDB_; | ||||||
|         int Create_AvatarTable(); |         std::unique_ptr<OpenWifi::BaseUserDB>           SubDB_; | ||||||
|         int Create_TokensTable(); |         std::unique_ptr<OpenWifi::BaseTokenDB>          UserTokenDB_; | ||||||
|         int Create_ActionLinkTable(); |         std::unique_ptr<OpenWifi::BaseTokenDB>          SubTokenDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::PreferencesDB>        PreferencesDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::PreferencesDB>        SubPreferencesDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::ActionLinkDB>         ActionLinksDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::AvatarDB>             AvatarDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::AvatarDB>             SubAvatarDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::LoginDB>              LoginDB_; | ||||||
|  |         std::unique_ptr<OpenWifi::LoginDB>              SubLoginDB_; | ||||||
|  |  | ||||||
|  |         std::unique_ptr<OpenWifi::UserCache>            UserCache_; | ||||||
|  |         std::unique_ptr<OpenWifi::UserCache>            SubCache_; | ||||||
|  |         std::unique_ptr<OpenWifi::TokenCache>           UserTokenCache_; | ||||||
|  |         std::unique_ptr<OpenWifi::TokenCache>           SubTokenCache_; | ||||||
|  |  | ||||||
|         Poco::Timer                     Timer_; |         Poco::Timer                     Timer_; | ||||||
|         Archiver                        Archiver_; |         Archiver                        Archiver_; | ||||||
|         std::unique_ptr<Poco::TimerCallback<Archiver>>   Archivercallback_; |         std::unique_ptr<Poco::TimerCallback<Archiver>>   Archivercallback_; | ||||||
|  |  | ||||||
|         /// This is to support a mistake that was deployed... |  | ||||||
|         void ReplaceOldDefaultUUID(); |  | ||||||
|    }; |    }; | ||||||
|  |  | ||||||
|     inline Storage * StorageService() { return Storage::instance(); }; |     inline auto StorageService() { return StorageService::instance(); }; | ||||||
|  |  | ||||||
| }  // namespace | }  // namespace | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										167
									
								
								src/TotpCache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								src/TotpCache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-01-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef OWSEC_TOTPCACHE_H | ||||||
|  | #define OWSEC_TOTPCACHE_H | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  | #include "seclibs/cpptotp/bytes.h" | ||||||
|  | #include "seclibs/qrcode/qrcodegen.hpp" | ||||||
|  | #include "seclibs/cpptotp/otp.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     class TotpCache : public SubSystemServer { | ||||||
|  |     public: | ||||||
|  |  | ||||||
|  |         struct Entry { | ||||||
|  |             bool        Subscriber=false; | ||||||
|  |             uint64_t    Start = 0; | ||||||
|  |             uint64_t    Done = 0 ; | ||||||
|  |             uint64_t    Verifications = 0 ; | ||||||
|  |             std::string Secret; | ||||||
|  |             std::string QRCode; | ||||||
|  |             std::string LastCode; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         static auto instance() { | ||||||
|  |             static auto instance = new TotpCache; | ||||||
|  |             return instance; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static std::string GenerateSecret(uint Size, std::string & Base32Secret) { | ||||||
|  |             std::string R; | ||||||
|  |  | ||||||
|  |             for(;Size;Size--) { | ||||||
|  |                 R += (char) MicroService::instance().Random(33,127); | ||||||
|  |             } | ||||||
|  |             Base32Secret = CppTotp::Bytes::toBase32( CppTotp::Bytes::ByteString{ (const u_char *)R.c_str()}); | ||||||
|  |             return R; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { | ||||||
|  |             std::string uri{ | ||||||
|  |                 "otpauth://totp/" + Issuer_ + ":" + | ||||||
|  |                 email + "?secret=" + Secret + "&issuer=" + Issuer_ | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             qrcodegen::QrCode qr0 = qrcodegen::QrCode::encodeText(uri.c_str(), qrcodegen::QrCode::Ecc::MEDIUM); | ||||||
|  |             std::string svg = qrcodegen::toSvgString(qr0, 4);  // See QrCodeGeneratorDemo | ||||||
|  |             return svg; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { | ||||||
|  |             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]{0}; | ||||||
|  |             sprintf(buffer,"%06u",p); | ||||||
|  |             Expecting = std::string(buffer); | ||||||
|  |             return Code == Expecting; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int Start() override { | ||||||
|  |             Issuer_ = MicroService::instance().ConfigGetString("totp.issuer","OpenWiFi"); | ||||||
|  |             return 0; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         void Stop() override { | ||||||
|  |  | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         inline bool StartValidation(const SecurityObjects::UserInfo &User, bool Subscriber, std::string & QRCode, bool Reset) { | ||||||
|  |             auto Hint = Cache_.find(User.id); | ||||||
|  |             if(Hint!=Cache_.end() && Hint->second.Subscriber==Subscriber) { | ||||||
|  |                 if(Reset) { | ||||||
|  |                     std::string Base32Secret; | ||||||
|  |                     Hint->second.Subscriber = Subscriber; | ||||||
|  |                     Hint->second.Start = OpenWifi::Now(); | ||||||
|  |                     Hint->second.Done = 0; | ||||||
|  |                     Hint->second.Verifications = 0; | ||||||
|  |                     Hint->second.Secret = GenerateSecret(20,Base32Secret); | ||||||
|  |                     Hint->second.QRCode = QRCode = GenerateQRCode(Base32Secret, User.email); | ||||||
|  |                     Hint->second.LastCode.clear(); | ||||||
|  |                 } else { | ||||||
|  |                     QRCode = Hint->second.QRCode; | ||||||
|  |                 } | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             std::string Base32Secret; | ||||||
|  |             auto Secret = GenerateSecret(20, Base32Secret); | ||||||
|  |             QRCode = GenerateQRCode(Base32Secret, User.email); | ||||||
|  |  | ||||||
|  |             Entry E{ .Subscriber = Subscriber, | ||||||
|  |                      .Start = OpenWifi::Now(), | ||||||
|  |                      .Done = 0, | ||||||
|  |                      .Verifications = 0, | ||||||
|  |                      .Secret = Secret, | ||||||
|  |                      .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, RESTAPI::Errors::msg & Error ) { | ||||||
|  |             auto Hint = Cache_.find(User.id); | ||||||
|  |             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)) { | ||||||
|  |                     NextIndex++; | ||||||
|  |                     Hint->second.Verifications++; | ||||||
|  |                     MoreCodes = true; | ||||||
|  |                     Hint->second.LastCode = Code; | ||||||
|  |                     return true; | ||||||
|  |                 } else if (NextIndex == 2 && Hint->second.Verifications == 1 && Code != Hint->second.LastCode && | ||||||
|  |                             ValidateCode(Hint->second.Secret, Code, Expecting) ) { | ||||||
|  |                     MoreCodes = false; | ||||||
|  |                     Hint->second.Done = Now; | ||||||
|  |                     return true; | ||||||
|  |                 } else { | ||||||
|  |                     if(!ValidateCode(Hint->second.Secret, Code, Expecting)) { | ||||||
|  |                         Error = RESTAPI::Errors::TOTInvalidCode; | ||||||
|  |                         return false; | ||||||
|  |                     } else if(NextIndex!=1 && NextIndex != 2) { | ||||||
|  |                         Error = RESTAPI::Errors::TOTInvalidIndex; | ||||||
|  |                         return false; | ||||||
|  |                     } else if(Code == Hint->second.LastCode) { | ||||||
|  |                         Error = RESTAPI::Errors::TOTRepeatedCode; | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     Error = RESTAPI::Errors::TOTInvalidProtocol; | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 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 = 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); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         std::map<std::string,Entry>     Cache_; | ||||||
|  |         std::string                     Issuer_; | ||||||
|  |  | ||||||
|  |         TotpCache() noexcept: | ||||||
|  |             SubSystemServer("TOTP-system", "TOTP-SVR", "totp") { | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     inline auto TotpCache() { return TotpCache::instance(); } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif //OWSEC_TOTPCACHE_H | ||||||
							
								
								
									
										93
									
								
								src/framework/API_Proxy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/framework/API_Proxy.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-30. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  | #include "Poco/JSON/Parser.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     inline void API_Proxy( Poco::Logger &Logger, | ||||||
|  |                     Poco::Net::HTTPServerRequest *Request, | ||||||
|  |                     Poco::Net::HTTPServerResponse *Response, | ||||||
|  |                     const char * ServiceType, | ||||||
|  |                     const char * PathRewrite, | ||||||
|  |                     uint64_t msTimeout_ = 10000 ) { | ||||||
|  |         try { | ||||||
|  |             auto Services = MicroService::instance().GetServices(ServiceType); | ||||||
|  |             for(auto const &Svc:Services) { | ||||||
|  |                 Poco::URI   SourceURI(Request->getURI()); | ||||||
|  |                 Poco::URI	DestinationURI(Svc.PrivateEndPoint); | ||||||
|  |                 DestinationURI.setPath(PathRewrite); | ||||||
|  |                 DestinationURI.setQuery(SourceURI.getQuery()); | ||||||
|  |  | ||||||
|  |                 // std::cout << "     Source: " << SourceURI.toString() << std::endl; | ||||||
|  |                 // std::cout << "Destination: " << DestinationURI.toString() << std::endl; | ||||||
|  |  | ||||||
|  |                 Poco::Net::HTTPSClientSession Session(DestinationURI.getHost(), DestinationURI.getPort()); | ||||||
|  |                 Session.setKeepAlive(true); | ||||||
|  |                 Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); | ||||||
|  |                 Poco::Net::HTTPRequest ProxyRequest(Request->getMethod(), | ||||||
|  |                                                     DestinationURI.getPathAndQuery(), | ||||||
|  |                                                     Poco::Net::HTTPMessage::HTTP_1_1); | ||||||
|  |                 if(Request->has("Authorization")) { | ||||||
|  |                     ProxyRequest.add("Authorization", Request->get("Authorization")); | ||||||
|  |                 } else { | ||||||
|  |                     ProxyRequest.add("X-API-KEY", Svc.AccessKey); | ||||||
|  |                     ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) { | ||||||
|  |                     Session.sendRequest(ProxyRequest); | ||||||
|  |                     Poco::Net::HTTPResponse ProxyResponse; | ||||||
|  |                     Session.receiveResponse(ProxyResponse); | ||||||
|  |                     Response->setStatus(ProxyResponse.getStatus()); | ||||||
|  |                     Response->send(); | ||||||
|  |                     return; | ||||||
|  |                 } else { | ||||||
|  |                     Poco::JSON::Parser P; | ||||||
|  |                     std::stringstream SS; | ||||||
|  |                     try { | ||||||
|  |                         auto Body = P.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |                         Poco::JSON::Stringifier::condense(Body,SS); | ||||||
|  |                         SS << "\r\n\r\n"; | ||||||
|  |                     } catch(const Poco::Exception &E) { | ||||||
|  |                         Logger.log(E); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if(SS.str().empty()) { | ||||||
|  |                         Session.sendRequest(ProxyRequest); | ||||||
|  |                     } else { | ||||||
|  |                         ProxyRequest.setContentType("application/json"); | ||||||
|  |                         ProxyRequest.setContentLength(SS.str().size()); | ||||||
|  |                         std::ostream & os = Session.sendRequest(ProxyRequest); | ||||||
|  |                         os << SS.str() ; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     Poco::Net::HTTPResponse ProxyResponse; | ||||||
|  |                     std::stringstream SSR; | ||||||
|  |                     try { | ||||||
|  |                         std::istream &ProxyResponseStream = Session.receiveResponse(ProxyResponse); | ||||||
|  |                         Poco::JSON::Parser  P2; | ||||||
|  |                         auto ProxyResponseBody = P2.parse(ProxyResponseStream).extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |                         Poco::JSON::Stringifier::condense(ProxyResponseBody,SSR); | ||||||
|  |                         Response->setContentType("application/json"); | ||||||
|  |                         Response->setContentLength(SSR.str().size()); | ||||||
|  |                         Response->setStatus(ProxyResponse.getStatus()); | ||||||
|  |                         Response->sendBuffer(SSR.str().c_str(),SSR.str().size()); | ||||||
|  |                         return; | ||||||
|  |                     } catch( const Poco::Exception & E) { | ||||||
|  |  | ||||||
|  |                     } | ||||||
|  |                     Response->setStatus(ProxyResponse.getStatus()); | ||||||
|  |                     Response->send(); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger.log(E); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user