mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 02:37:56 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			v2.7.0-RC1
			...
			release/v2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 2ec24294b8 | ||
|   | 2d3c211c4e | ||
|   | ec0f877044 | ||
|   | 96b712eba1 | ||
|   | 8b45bfd812 | ||
|   | e0a57a4846 | ||
|   | a72e286a83 | 
							
								
								
									
										35
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,7 +13,6 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - main | ||||
|       - 'release/*' | ||||
|  | ||||
| defaults: | ||||
|   run: | ||||
| @@ -40,16 +39,6 @@ jobs: | ||||
|         registry_user: ucentral | ||||
|         registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} | ||||
|  | ||||
|     - name: Notify on failure via Slack | ||||
|       if: failure() && github.ref == 'refs/heads/main' | ||||
|       uses: rtCamp/action-slack-notify@v2 | ||||
|       env: | ||||
|         SLACK_USERNAME: GitHub Actions failure notifier | ||||
|         SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | ||||
|         SLACK_COLOR: "${{ job.status }}" | ||||
|         SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png | ||||
|         SLACK_TITLE: Docker build failed for OWSec service | ||||
|  | ||||
|   trigger-testing: | ||||
|     if: startsWith(github.ref, 'refs/pull/') | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -78,26 +67,4 @@ jobs: | ||||
|         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"}' | ||||
|         inputs: '{"owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owgwui_version": "${{ env.BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "main", "owprovui_version": "main"}' | ||||
|   | ||||
							
								
								
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,6 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - main | ||||
|       - 'release/*' | ||||
|     types: [ closed ] | ||||
|  | ||||
| defaults: | ||||
| @@ -17,10 +16,4 @@ jobs: | ||||
|     steps: | ||||
|       - run: | | ||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||
|  | ||||
|           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 | ||||
|           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG" | ||||
|   | ||||
							
								
								
									
										46
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,46 +0,0 @@ | ||||
| name: Release chart package | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - 'v*' | ||||
|  | ||||
| defaults: | ||||
|   run: | ||||
|     shell: bash | ||||
|  | ||||
| jobs: | ||||
|   helm-package: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     env: | ||||
|       HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||
|       HELM_REPO_USERNAME: ucentral | ||||
|     steps: | ||||
|       - name: Checkout uCentral assembly chart repo | ||||
|         uses: actions/checkout@v2 | ||||
|         with: | ||||
|           path: wlan-cloud-ucentralsec | ||||
|  | ||||
|       - name: Build package | ||||
|         working-directory: wlan-cloud-ucentralsec/helm | ||||
|         run: | | ||||
|           helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0 | ||||
|           helm repo add bitnami https://charts.bitnami.com/bitnami | ||||
|           helm repo update | ||||
|           helm dependency update | ||||
|           mkdir dist | ||||
|           helm package . -d dist | ||||
|  | ||||
|       - name: Generate GitHub release body | ||||
|         working-directory: wlan-cloud-ucentralsec/helm | ||||
|         run: | | ||||
|           pip3 install yq -q | ||||
|           echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:$GITHUB_REF_NAME" > release.txt | ||||
|           echo "Helm charted may be attached to this release" >> release.txt | ||||
|           echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt | ||||
|  | ||||
|       - name: Create GitHub release | ||||
|         uses: softprops/action-gh-release@v1 | ||||
|         with: | ||||
|           body_path: wlan-cloud-ucentralsec/helm/release.txt | ||||
|           files: wlan-cloud-ucentralsec/helm/dist/* | ||||
| @@ -1,5 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.13) | ||||
| project(owsec VERSION 2.7.0) | ||||
| project(owsec VERSION 2.5.0) | ||||
|  | ||||
| set(CMAKE_CXX_STANDARD 17) | ||||
|  | ||||
| @@ -48,15 +48,12 @@ set(BUILD_SHARED_LIBS 1) | ||||
|  | ||||
| add_definitions(-DTIP_SECURITY_SERVICE="1") | ||||
|  | ||||
| add_compile_options(-Wall -Wextra) | ||||
| if(ASAN) | ||||
|     add_compile_options(-fsanitize=address) | ||||
|     add_link_options(-fsanitize=address) | ||||
| endif() | ||||
|  | ||||
| set(Boost_USE_STATIC_LIBS OFF) | ||||
| set(Boost_USE_MULTITHREADED ON) | ||||
| set(Boost_USE_STATIC_RUNTIME OFF) | ||||
| find_package(Boost REQUIRED system) | ||||
| find_package(OpenSSL REQUIRED) | ||||
| find_package(ZLIB REQUIRED) | ||||
| find_package(fmt  REQUIRED) | ||||
| find_package(AWSSDK     REQUIRED COMPONENTS sns) | ||||
| find_package(nlohmann_json  REQUIRED) | ||||
| find_package(CppKafka REQUIRED) | ||||
| @@ -75,9 +72,10 @@ add_executable( owsec | ||||
|         src/framework/KafkaTopics.h | ||||
|         src/framework/MicroService.h | ||||
|         src/framework/orm.h | ||||
|         src/framework/RESTAPI_errors.h | ||||
|         src/framework/RESTAPI_protocol.h | ||||
|         src/framework/StorageClass.h | ||||
|         src/framework/ow_constants.h | ||||
|         src/framework/WebSocketClientNotifications.h | ||||
|         src/framework/uCentral_Protocol.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 | ||||
| @@ -124,16 +122,12 @@ add_executable( owsec | ||||
|         src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h | ||||
|         src/storage/orm_avatar.cpp src/storage/orm_avatar.h | ||||
|         src/SpecialUserHelpers.h | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.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) | ||||
|  | ||||
| if(NOT SMALL_BUILD) | ||||
|     target_link_libraries(owsec PUBLIC | ||||
|             ${Poco_LIBRARIES} | ||||
|             ${MySQL_LIBRARIES} | ||||
|             ${ZLIB_LIBRARIES} | ||||
|             CppKafka::cppkafka | ||||
|             ${AWSSDK_LINK_LIBRARIES} | ||||
|             fmt::fmt | ||||
|             ${Poco_LIBRARIES} ${Boost_LIBRARIES} ${MySQL_LIBRARIES}  ${ZLIB_LIBRARIES} | ||||
|             CppKafka::cppkafka ${AWSSDK_LINK_LIBRARIES} | ||||
|             ) | ||||
|     if(UNIX AND NOT APPLE) | ||||
|         target_link_libraries(owsec PUBLIC PocoJSON) | ||||
|   | ||||
							
								
								
									
										56
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,11 +1,4 @@ | ||||
| ARG ALPINE_VERSION=3.16.2 | ||||
| ARG POCO_VERSION=poco-tip-v1 | ||||
| ARG FMTLIB_VERSION=9.0.0 | ||||
| ARG CPPKAFKA_VERSION=tip-v1 | ||||
| ARG JSON_VALIDATOR_VERSION=2.1.0 | ||||
| ARG AWS_SDK_VERSION=1.9.315 | ||||
|  | ||||
| FROM alpine:$ALPINE_VERSION AS build-base | ||||
| FROM alpine:3.15 AS build-base | ||||
|  | ||||
| RUN apk add --update --no-cache \ | ||||
|     make cmake g++ git \ | ||||
| @@ -16,10 +9,8 @@ RUN apk add --update --no-cache \ | ||||
|  | ||||
| FROM build-base AS poco-build | ||||
|  | ||||
| ARG POCO_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco | ||||
| ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json | ||||
| RUN git clone https://github.com/stephb9959/poco /poco | ||||
|  | ||||
| WORKDIR /poco | ||||
| RUN mkdir cmake-build | ||||
| @@ -28,26 +19,10 @@ RUN cmake .. | ||||
| RUN cmake --build . --config Release -j8 | ||||
| RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS fmtlib-build | ||||
|  | ||||
| ARG FMTLIB_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json | ||||
| RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib | ||||
|  | ||||
| WORKDIR /fmtlib | ||||
| RUN mkdir cmake-build | ||||
| WORKDIR cmake-build | ||||
| RUN cmake .. | ||||
| RUN make | ||||
| RUN make install | ||||
|  | ||||
| FROM build-base AS cppkafka-build | ||||
|  | ||||
| ARG CPPKAFKA_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka | ||||
| ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json | ||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | ||||
|  | ||||
| WORKDIR /cppkafka | ||||
| RUN mkdir cmake-build | ||||
| @@ -58,10 +33,8 @@ RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS json-schema-validator-build | ||||
|  | ||||
| ARG JSON_VALIDATOR_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json | ||||
| RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator | ||||
| 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 | ||||
|  | ||||
| WORKDIR /json-schema-validator | ||||
| RUN mkdir cmake-build | ||||
| @@ -72,10 +45,8 @@ RUN make install | ||||
|  | ||||
| FROM build-base AS aws-sdk-cpp-build | ||||
|  | ||||
| ARG AWS_SDK_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json | ||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp | ||||
| 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 | ||||
|  | ||||
| WORKDIR /aws-sdk-cpp | ||||
| RUN mkdir cmake-build | ||||
| @@ -103,9 +74,6 @@ COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib | ||||
| COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include | ||||
| COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib | ||||
|  | ||||
| COPY --from=fmtlib-build /usr/local/include /usr/local/include | ||||
| COPY --from=fmtlib-build /usr/local/lib /usr/local/lib | ||||
|  | ||||
| WORKDIR /owsec | ||||
| RUN mkdir cmake-build | ||||
| WORKDIR /owsec/cmake-build | ||||
| @@ -114,7 +82,7 @@ RUN cmake .. \ | ||||
|           -DBUILD_SHARED_LIBS=ON | ||||
| RUN cmake --build . --config Release -j8 | ||||
|  | ||||
| FROM alpine:$ALPINE_VERSION | ||||
| FROM alpine:3.15 | ||||
|  | ||||
| ENV OWSEC_USER=owsec \ | ||||
|     OWSEC_ROOT=/owsec-data \ | ||||
| @@ -142,8 +110,8 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr | ||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem | ||||
|  | ||||
| COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec | ||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib | ||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib | ||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib/ | ||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib/ | ||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib | ||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib | ||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib | ||||
|   | ||||
							
								
								
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
								
							| @@ -1,37 +0,0 @@ | ||||
| # Operator Support | ||||
| In order to support multiple tenants and operators, you must prepare the security service to serve | ||||
| customized e-mails and messages. | ||||
|  | ||||
| ## Structure for `templates` | ||||
| Any file in the root of the directory will be used as defaults. The following files must be present: | ||||
| - email_invitation.html/txt : This email message will be sent to a newly added user.  | ||||
| - email_verification.html/txt : This email is sent when an email verification is required. | ||||
| - password_reset.html/txt : This is sent when a pasword reset is requested. | ||||
| - verification_code.html/txt : This is used during MFA when email based. | ||||
| - signup_verification.html/txt : This email is send to a new subscriber who signed up for service. | ||||
| - sub_email_verification.html/txt : This is sent to a subscriber requiring an email verification. | ||||
| - sub_verification_code.html/txt : This is used during MFA when email based for a subscriber. | ||||
| - logo.jpg : The default logo to use in any of these emails. | ||||
|  | ||||
| ## Structure for `wwwassets` | ||||
| Any file in the root of the directory will be used as defaults. The following files must be present: | ||||
| - email_verification_error.html : Used when email verification has failed. | ||||
| - email_verification_success.html : Used when emil verification has succeeded. | ||||
| - invitation_error.html : | ||||
| - invitation_success.html : | ||||
| - password_policy.html : | ||||
| - password_reset.html : | ||||
| - password_reset_success.html : | ||||
| - password_reset_error.html : | ||||
| - signup_verification.html : | ||||
| - signup_verification_error.html : | ||||
| - signup_verification_success.html : | ||||
| - favicon.ico : icon for the application | ||||
| - 404_error.html : your customized 404 page | ||||
| - the_logo : the logo to use. | ||||
|  | ||||
| ## For tenants | ||||
| When creating a tenant/operator, you must create a subdirectory inside each `wwwassets` and `templates` and replicate  | ||||
| all the files that appear at the root level. You need to use the short Operator name (also known as RegistrantId in the API). This means  | ||||
| no spaces, all lowercase characters and numbers. No special characters: 0-9 and a-z.  | ||||
|  | ||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							| @@ -136,7 +136,7 @@ docker run --rm -ti \ | ||||
| This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running | ||||
| in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. | ||||
|  | ||||
| ``` | ||||
| ```asm | ||||
| openwifi.kafka.group.id = security | ||||
| openwifi.kafka.client.id = security1 | ||||
| openwifi.kafka.enable = true | ||||
| @@ -166,7 +166,7 @@ Here are the parameters for the public interface. The important files are: | ||||
| - `restapi-key.pem` : the key associated with this certificate | ||||
| - `openwifi.restapi.host.0.key.password` : if you key is password protected, you may supply that password here. | ||||
|  | ||||
| ``` | ||||
| ```asm | ||||
| openwifi.restapi.host.0.backlog = 100 | ||||
| openwifi.restapi.host.0.security = relaxed | ||||
| openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | ||||
| @@ -181,7 +181,7 @@ openwifi.restapi.host.0.key.password = mypassword | ||||
| The private interface is used for service-to-service communication. You can use self-signed certificates here or letsencrypt. The file names are similar  | ||||
| to the filenames used in the previous section. | ||||
|  | ||||
| ``` | ||||
| ```asm | ||||
| openwifi.internal.restapi.host.0.backlog = 100 | ||||
| openwifi.internal.restapi.host.0.security = relaxed | ||||
| openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem | ||||
| @@ -196,7 +196,7 @@ openwifi.internal.restapi.host.0.key.password = mypassword | ||||
| Here are other important values you must set. | ||||
|  | ||||
|  | ||||
| ``` | ||||
| ```asm | ||||
| openwifi.system.data = $OWSEC_ROOT/data | ||||
| openwifi.system.uri.private = https://localhost:17001 | ||||
| openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001 | ||||
| @@ -221,8 +221,7 @@ an SMS provider must be configured. At present time, 2 providers are supported: | ||||
| #### AWS SMS | ||||
| For SNS you must create an IAM ID that has sns:sendmessage rights.   | ||||
|  | ||||
| ``` | ||||
| smssender.enabled = true | ||||
| ```asm | ||||
| smssender.provider = aws | ||||
| smssender.aws.secretkey = *************************************** | ||||
| smssender.aws.accesskey = *************************************** | ||||
| @@ -232,8 +231,7 @@ smssender.aws.region = ************** | ||||
| #### Twilio | ||||
| For Twilio, you must provide the following | ||||
|  | ||||
| ``` | ||||
| smssender.enabled = true | ||||
| ```asm | ||||
| smssender.provider = twilio | ||||
| smssender.twilio.sid = *********************** | ||||
| smssender.twilio.token = ********************** | ||||
| @@ -245,8 +243,7 @@ smssender.twilio.phonenumber = +18888888888 | ||||
| with GMail and AWS SES. For each, you must obtain the proper credentials and insert them in this configuration as well | ||||
| as the proper mail host. | ||||
|  | ||||
| ``` | ||||
| mailer.enabled = true | ||||
| ```asm | ||||
| mailer.hostname = smtp.gmail.com | ||||
| mailer.username = ************************ | ||||
| mailer.password = ************************ | ||||
| @@ -257,10 +254,10 @@ 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  | ||||
| In order to use the Google Time-based One-Time Password (TOTP), the user must down load the Goole Authenticator  | ||||
| on any other app that support the TOTP protocol. You should include the following in your configuration | ||||
|  | ||||
| ``` | ||||
| ```asm | ||||
| totp.issuer = OrgName | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then | ||||
|     update-ca-certificates | ||||
| fi | ||||
|  | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; then | ||||
|   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \ | ||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ | ||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ | ||||
| @@ -42,10 +42,6 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||
|   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ | ||||
|   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ | ||||
|   KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ | ||||
|   KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \ | ||||
|   KAFKA_SSL_CERTIFICATE_LOCATION=${KAFKA_SSL_CERTIFICATE_LOCATION:-""} \ | ||||
|   KAFKA_SSL_KEY_LOCATION=${KAFKA_SSL_KEY_LOCATION:-""} \ | ||||
|   KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \ | ||||
|   DOCUMENT_POLICY_ACCESS=${DOCUMENT_POLICY_ACCESS:-"\$OWSEC_ROOT/persist/wwwassets/access_policy.html"} \ | ||||
|   DOCUMENT_POLICY_PASSWORD=${DOCUMENT_POLICY_PASSWORD:-"\$OWSEC_ROOT/persist/wwwassets/password_policy.html"} \ | ||||
|   STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ | ||||
|   | ||||
							
								
								
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1 @@ | ||||
| *.swp | ||||
| Chart.lock | ||||
| charts/ | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| {{- $root := . -}} | ||||
| {{- $storageType := index .Values.configProperties "storage.type" -}} | ||||
| --- | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| @@ -47,39 +46,6 @@ spec: | ||||
|             - -timeout | ||||
|             - 600s | ||||
|  | ||||
| {{- if eq $storageType "postgresql" }} | ||||
|         - name: wait-postgres | ||||
|           image: "{{ .Values.images.owsec.repository }}:{{ .Values.images.owsec.tag }}" | ||||
|           imagePullPolicy: {{ .Values.images.owsec.pullPolicy }} | ||||
|           command: | ||||
|             - /wait-for-postgres.sh | ||||
|             - {{ index .Values.configProperties "storage.type.postgresql.host" }} | ||||
|             - echo | ||||
|             - "PostgreSQL is ready" | ||||
|           env: | ||||
|             - name: KUBERNETES_DEPLOYED | ||||
|               value: "{{ now }}" | ||||
|           {{- range $key, $value := .Values.public_env_variables }} | ||||
|             - name: {{ $key }} | ||||
|               value: {{ $value | quote }} | ||||
|           {{- end }} | ||||
|           {{- range $key, $value := .Values.secret_env_variables }} | ||||
|             - name: {{ $key }} | ||||
|               valueFrom: | ||||
|                 secretKeyRef: | ||||
|                   name: {{ include "owsec.fullname" $root }}-env | ||||
|                   key: {{ $key }} | ||||
|           {{- end }} | ||||
|           volumeMounts: | ||||
|           {{- range .Values.volumes.owsec }} | ||||
|           - name: {{ .name }} | ||||
|             mountPath: {{ .mountPath }} | ||||
|             {{- if .subPath }} | ||||
|             subPath: {{ .subPath }} | ||||
|             {{- end }} | ||||
|           {{- end }} | ||||
| {{- end }} | ||||
|  | ||||
|       containers: | ||||
|  | ||||
|         - name: owsec | ||||
|   | ||||
| @@ -9,7 +9,7 @@ fullnameOverride: "" | ||||
| images: | ||||
|   owsec: | ||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||
|     tag: v2.7.0-RC1 | ||||
|     tag: v2.5.2 | ||||
|     pullPolicy: Always | ||||
| #    regcred: | ||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||
| @@ -167,10 +167,6 @@ configProperties: | ||||
|   openwifi.kafka.brokerlist: localhost:9092 | ||||
|   openwifi.kafka.auto.commit: false | ||||
|   openwifi.kafka.queue.buffering.max.ms: 50 | ||||
|   openwifi.kafka.ssl.ca.location: "" | ||||
|   openwifi.kafka.ssl.certificate.location: "" | ||||
|   openwifi.kafka.ssl.key.location: "" | ||||
|   openwifi.kafka.ssl.key.password: "" | ||||
|   # Storage | ||||
|   storage.type: sqlite # (sqlite|postgresql|mysql|odbc) | ||||
|   ## SQLite | ||||
|   | ||||
| @@ -66,7 +66,6 @@ components: | ||||
|                   - 11    # BAD_MFA_TRANSACTION | ||||
|                   - 12    # MFA_FAILURE | ||||
|                   - 13    # SECURITY_SERVICE_UNREACHABLE | ||||
|                   - 14    # CANNOT REFRESH TOKEN | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
| @@ -121,15 +120,6 @@ components: | ||||
|         userId: support@example.com | ||||
|         password: support | ||||
|  | ||||
|     WebTokenRefreshRequest: | ||||
|       type: object | ||||
|       properties: | ||||
|         userId: | ||||
|           type: string | ||||
|           default: support@example.com | ||||
|         refresh_token: | ||||
|           type: string | ||||
|  | ||||
|     WebTokenResult: | ||||
|       description: Login and Refresh Tokens to be used in subsequent API calls. | ||||
|       type: object | ||||
| @@ -365,9 +355,6 @@ components: | ||||
|           format: int64 | ||||
|         userTypeProprietaryInfo: | ||||
|           $ref: '#/components/schemas/UserLoginLoginExtensions' | ||||
|         signupUUID: | ||||
|           type: string | ||||
|           format: uuid | ||||
|  | ||||
|     UserList: | ||||
|       type: object | ||||
| @@ -746,12 +733,6 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: grant_type | ||||
|           schema: | ||||
|             type: string | ||||
|             example: refresh_token | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User id and password | ||||
|         required: true | ||||
| @@ -761,7 +742,6 @@ paths: | ||||
|               oneOf: | ||||
|                 - $ref: '#/components/schemas/WebTokenRequest' | ||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||
|                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: successful operation | ||||
| @@ -811,12 +791,6 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: grant_type | ||||
|           schema: | ||||
|             type: string | ||||
|             example: refresh_token | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User id and password | ||||
|         required: true | ||||
| @@ -826,7 +800,6 @@ paths: | ||||
|               oneOf: | ||||
|                 - $ref: '#/components/schemas/WebTokenRequest' | ||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' | ||||
|                 - $ref: '#/components/schemas/WebTokenRefreshRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: successful operation | ||||
| @@ -947,16 +920,6 @@ paths: | ||||
|             type: string | ||||
|             example: id1,id2,id3,id4,id5 | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: nameSearch | ||||
|           schema: | ||||
|             type: string | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: emailSearch | ||||
|           schema: | ||||
|             type: string | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserList' | ||||
| @@ -1003,16 +966,6 @@ paths: | ||||
|             type: string | ||||
|             example: id1,id2,id3,id4,id5 | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: nameSearch | ||||
|           schema: | ||||
|             type: string | ||||
|         - in: query | ||||
|           description: Name matching | ||||
|           name: emailSearch | ||||
|           schema: | ||||
|             type: string | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserList' | ||||
| @@ -1111,18 +1064,6 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: forgotPassword | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: resetMFA | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User details (some fields are ignored during update) | ||||
|         content: | ||||
| @@ -1227,18 +1168,6 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: forgotPassword | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: resetMFA | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: User details (some fields are ignored during update) | ||||
|         content: | ||||
| @@ -1536,8 +1465,8 @@ paths: | ||||
|           schema: | ||||
|             type: integer | ||||
|             format: int64 | ||||
|           required: required | ||||
|           example: 1,2,3 | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           description: Succesful posting of response. | ||||
| @@ -1555,87 +1484,6 @@ paths: | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|  | ||||
|   /signup: | ||||
|     post: | ||||
|       tags: | ||||
|         - Subscriber Registration | ||||
|       summary: This call allows a new subscriber to register themselves and their devices. | ||||
|       operationId: postSignup | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: email | ||||
|           schema: | ||||
|             type: string | ||||
|             format: email | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: signupUUID | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/UserInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - Subscriber Registration | ||||
|       summary: modify the signup command in play | ||||
|       operationId: modifySignup | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: signupUUID | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: operation | ||||
|           schema: | ||||
|             type: string | ||||
|             enum: | ||||
|               - cancel | ||||
|               - success | ||||
|               - inprogress | ||||
|               - failed | ||||
|               - poll | ||||
|               - emailVerified | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               type: object | ||||
|               properties: | ||||
|                 reason: | ||||
|                   type: string | ||||
|                 time: | ||||
|                   type: integer | ||||
|                   format: int64 | ||||
|                 errorCode: | ||||
|                   type: integer | ||||
|                   format: int32 | ||||
|         required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|  | ||||
|  | ||||
|   ######################################################################################### | ||||
|   ## | ||||
|   ## These are endpoints that all services in the uCentral stack must provide | ||||
|   | ||||
| @@ -82,11 +82,6 @@ openwifi.kafka.enable = true | ||||
| openwifi.kafka.brokerlist = a1.arilia.com:9092 | ||||
| openwifi.kafka.auto.commit = false | ||||
| openwifi.kafka.queue.buffering.max.ms = 50 | ||||
| openwifi.kafka.ssl.ca.location = | ||||
| openwifi.kafka.ssl.certificate.location = | ||||
| openwifi.kafka.ssl.key.location = | ||||
| openwifi.kafka.ssl.key.password = | ||||
|  | ||||
| openwifi.document.policy.access = /wwwassets/access_policy.html | ||||
| openwifi.document.policy.password = /wwwassets/password_policy.html | ||||
| openwifi.avatar.maxsize = 2000000 | ||||
|   | ||||
| @@ -82,10 +82,6 @@ openwifi.kafka.enable = ${KAFKA_ENABLE} | ||||
| openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST} | ||||
| openwifi.kafka.auto.commit = false | ||||
| openwifi.kafka.queue.buffering.max.ms = 50 | ||||
| openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION} | ||||
| openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION} | ||||
| openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION} | ||||
| openwifi.kafka.ssl.key.password = ${KAFKA_SSL_KEY_PASSWORD} | ||||
|  | ||||
| openwifi.document.policy.access = ${DOCUMENT_POLICY_ACCESS} | ||||
| openwifi.document.policy.password = ${DOCUMENT_POLICY_PASSWORD} | ||||
|   | ||||
| @@ -18,7 +18,6 @@ namespace OpenWifi { | ||||
|             CREATE | ||||
|         }; | ||||
| /* | ||||
|  *  0) You can only delete yourself if you are a subscriber | ||||
|     1) You cannot delete yourself | ||||
|     2) If you are root, you can do anything. | ||||
|     3) You can do anything to yourself | ||||
| @@ -31,11 +30,6 @@ namespace OpenWifi { | ||||
|  | ||||
|  */ | ||||
|         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { | ||||
|  | ||||
|             // rule 0 | ||||
|             if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE) | ||||
|                 return true; | ||||
|  | ||||
|             //  rule 1 | ||||
|             if(User.id == Target.id && Op==DELETE) | ||||
|                 return false; | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include "ActionLinkManager.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -25,7 +24,6 @@ namespace OpenWifi { | ||||
|  | ||||
|     void ActionLinkManager::run() { | ||||
|         Running_ = true ; | ||||
|         Utils::SetThreadName("action-mgr"); | ||||
|  | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(2000); | ||||
| @@ -50,63 +48,39 @@ namespace OpenWifi { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD || | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL || | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) && | ||||
|                         (OpenWifi::Now()-i.created)>(24*60*60)) { | ||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { | ||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 switch(i.action) { | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) { | ||||
|                                 Logger().information(fmt::format("Send password reset link to {}",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||
|                                 Logger().information(Poco::format("Send password reset link to %s",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) { | ||||
|                                 Logger().information(fmt::format("Send email verification link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: { | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) { | ||||
|                                 Logger().information(fmt::format("Send new subscriber email invitation link to {}",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||
|                                 Logger().information(Poco::format("Send email verification link to %s",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: { | ||||
|                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                                 Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||
|                                 Logger().information(Poco::format("Send subscriber password reset link to %s",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: { | ||||
|                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                                 Logger().information(fmt::format("Send subscriber email verification link to {}",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|                         break; | ||||
|  | ||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: { | ||||
|                         auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|                         if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||
|                             Logger().information(fmt::format("Send new subscriber email verification link to {}",UInfo.email)); | ||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||
|                                 Logger().information(Poco::format("Send subscriber email verification link to %s",UInfo.email)); | ||||
|                             } | ||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||
|                         } | ||||
|   | ||||
| @@ -12,14 +12,21 @@ namespace OpenWifi { | ||||
|     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||
|     public: | ||||
|  | ||||
| /*        enum Actions { | ||||
|             FORGOT_PASSWORD, | ||||
|             VERIFY_EMAIL, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_VERIFY_EMAIL | ||||
|         }; | ||||
| */ | ||||
|         static ActionLinkManager * instance() { | ||||
|             static auto instance_ = new ActionLinkManager; | ||||
|             static auto * instance_ = new ActionLinkManager; | ||||
|             return instance_; | ||||
|         } | ||||
|  | ||||
|         int Start() final; | ||||
|         void Stop() final; | ||||
|         void run() final; | ||||
|         void run(); | ||||
|  | ||||
|     private: | ||||
|         Poco::Thread        Thr_; | ||||
|   | ||||
| @@ -20,7 +20,6 @@ | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "MFAServer.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -43,21 +42,20 @@ namespace OpenWifi { | ||||
| 		return 1;	// some compilers complain... | ||||
| 	} | ||||
|  | ||||
|     static const std::string DefaultPassword_8_u_l_n_1{"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\.\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"}; | ||||
|  | ||||
|     int AuthService::Start() { | ||||
| 		Signer_.setRSAKey(MicroService::instance().Key()); | ||||
| 		Signer_.addAllAlgorithms(); | ||||
| 		Logger().notice("Starting..."); | ||||
|         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); | ||||
|         RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600); | ||||
|         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); | ||||
|  | ||||
|         AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||
|         PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1); | ||||
|         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||
|         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||
|  | ||||
|         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1); | ||||
|         SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html"); | ||||
|         SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html"); | ||||
|         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||
|         SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html"); | ||||
|         SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html"); | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
| @@ -66,82 +64,6 @@ namespace OpenWifi { | ||||
| 		Logger().notice("Stopping..."); | ||||
|     } | ||||
|  | ||||
|     bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) { | ||||
|         try { | ||||
|             std::string CallToken; | ||||
|             Poco::Net::OAuth20Credentials Auth(Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 CallToken = Auth.getBearerToken(); | ||||
|             } | ||||
|  | ||||
|             if (CallToken.empty()) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) { | ||||
|                 auto now = OpenWifi::Now(); | ||||
|  | ||||
|                 //  Create a new token | ||||
|                 auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM); | ||||
|                 auto NewRefreshToken = RefreshToken; | ||||
|                 if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) { | ||||
|                     NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM); | ||||
|                     UI.webtoken.lastRefresh_ = now; | ||||
|                 } | ||||
|  | ||||
|                 StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ ); | ||||
|                 UI.webtoken.access_token_ = NewToken; | ||||
|                 UI.webtoken.refresh_token_ = NewRefreshToken; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|  | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) { | ||||
|         try { | ||||
|             std::string CallToken; | ||||
|             Poco::Net::OAuth20Credentials Auth(Request); | ||||
|             if (Auth.getScheme() == "Bearer") { | ||||
|                 CallToken = Auth.getBearerToken(); | ||||
|             } | ||||
|  | ||||
|             if (CallToken.empty()) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             uint64_t                    RevocationDate=0; | ||||
|             std::string                 UserId; | ||||
|             if(StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) { | ||||
|                 auto now = OpenWifi::Now(); | ||||
|  | ||||
|                 //  Create a new token | ||||
|                 auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM); | ||||
|                 auto NewRefreshToken = RefreshToken; | ||||
|                 if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) { | ||||
|                     NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM); | ||||
|                     UI.webtoken.lastRefresh_ = now; | ||||
|                 } | ||||
|  | ||||
|                 StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ ); | ||||
|                 UI.webtoken.access_token_ = NewToken; | ||||
|                 UI.webtoken.refresh_token_ = NewRefreshToken; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|  | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard	Guard(Mutex_); | ||||
| @@ -163,8 +85,7 @@ namespace OpenWifi { | ||||
|             if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||
|                 if(RevocationDate!=0) | ||||
|                     return false; | ||||
|                 auto now=OpenWifi::Now(); | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); | ||||
|                 if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) { | ||||
|                     UInfo.webtoken = WT; | ||||
|                     SessionToken = CallToken; | ||||
| @@ -199,8 +120,7 @@ namespace OpenWifi { | ||||
|             if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | ||||
|                 if(RevocationDate!=0) | ||||
|                     return false; | ||||
|                 auto now=OpenWifi::Now(); | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < now; | ||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); | ||||
|                 if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) { | ||||
|                     UInfo.webtoken = WT; | ||||
|                     SessionToken = CallToken; | ||||
| @@ -260,7 +180,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AuthService::Logout(const std::string &Token,[[maybe_unused]]  bool EraseFromCache) { | ||||
|     void AuthService::Logout(const std::string &Token, bool EraseFromCache) { | ||||
| 		std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
|         try { | ||||
| @@ -272,7 +192,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AuthService::SubLogout(const std::string &Token, [[maybe_unused]] bool EraseFromCache) { | ||||
|     void AuthService::SubLogout(const std::string &Token, bool EraseFromCache) { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
|         try { | ||||
| @@ -284,8 +204,8 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     [[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())); | ||||
|     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { | ||||
|         std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand())); | ||||
|         HMAC_.update(Identity); | ||||
|         return Poco::DigestEngine::digestToHex(HMAC_.digest()); | ||||
|     } | ||||
| @@ -305,7 +225,7 @@ namespace OpenWifi { | ||||
| 		T.payload().set("identity", Identity); | ||||
| 		T.setIssuedAt(Poco::Timestamp()); | ||||
| 		T.setExpiration(Poco::Timestamp() + (long long)TokenAging_); | ||||
| 		std::string JWT = MicroService::instance().Sign(T,Poco::JWT::Signer::ALGO_RS256); | ||||
| 		std::string JWT = Signer_.sign(T,Poco::JWT::Signer::ALGO_RS256); | ||||
|  | ||||
| 		return JWT; | ||||
|     } | ||||
| @@ -472,7 +392,7 @@ namespace OpenWifi { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired ) | ||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
| @@ -501,23 +421,24 @@ namespace OpenWifi { | ||||
|                     UInfo.webtoken.errorCode = 1; | ||||
|                     return PASSWORD_ALREADY_USED; | ||||
|                 } | ||||
|                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); | ||||
|                 UInfo.userinfo.changePassword = false; | ||||
|                 UInfo.userinfo.modified = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.modified = std::time(nullptr); | ||||
|                 StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo); | ||||
|             } | ||||
|  | ||||
|             //  so we have a good password, password up date has taken place if need be, now generate the token. | ||||
|             UInfo.userinfo.lastLogin=OpenWifi::Now(); | ||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||
|             StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); | ||||
|             CreateToken(UserName, UInfo ); | ||||
|  | ||||
|             return SUCCESS; | ||||
|         } | ||||
|  | ||||
|         return INVALID_CREDENTIALS; | ||||
|     } | ||||
|  | ||||
|     UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired ) | ||||
|     UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||
|     { | ||||
|         std::lock_guard		Guard(Mutex_); | ||||
|  | ||||
| @@ -546,14 +467,14 @@ namespace OpenWifi { | ||||
|                     UInfo.webtoken.errorCode = 1; | ||||
|                     return PASSWORD_ALREADY_USED; | ||||
|                 } | ||||
|                 UInfo.userinfo.lastPasswordChange = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); | ||||
|                 UInfo.userinfo.changePassword = false; | ||||
|                 UInfo.userinfo.modified = OpenWifi::Now(); | ||||
|                 UInfo.userinfo.modified = std::time(nullptr); | ||||
|                 StorageService()->SubDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo); | ||||
|             } | ||||
|  | ||||
|             //  so we have a good password, password up date has taken place if need be, now generate the token. | ||||
|             UInfo.userinfo.lastLogin=OpenWifi::Now(); | ||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||
|             StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); | ||||
|             CreateSubToken(UserName, UInfo ); | ||||
|  | ||||
| @@ -563,62 +484,29 @@ namespace OpenWifi { | ||||
|         return INVALID_CREDENTIALS; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) { | ||||
|         auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp,":"); | ||||
|         if(UInfo.userinfo.signingUp.empty() || OperatorParts.count()!=2) { | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs); | ||||
|         } else { | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) { | ||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||
|         SecurityObjects::UserInfo   UInfo; | ||||
|  | ||||
|         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { | ||||
|             switch (Reason) { | ||||
|  | ||||
|                 case MessagingTemplates::FORGOT_PASSWORD: { | ||||
|                 case FORGOT_PASSWORD: { | ||||
|                         MessageAttributes Attrs; | ||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                         Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                         Attrs[SUBJECT] = "Password reset link"; | ||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs); | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||
|                     } | ||||
|                     break; | ||||
|  | ||||
|                 case MessagingTemplates::EMAIL_VERIFICATION: { | ||||
|                 case EMAIL_VERIFICATION: { | ||||
|                         MessageAttributes Attrs; | ||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                         Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                         Attrs[SUBJECT] = "e-mail Address Verification"; | ||||
|                         Attrs[SUBJECT] = "EMail Address Verification"; | ||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs); | ||||
|                         UInfo.waitingForEmailCheck = true; | ||||
|                     } | ||||
|                     break; | ||||
|  | ||||
|                 case MessagingTemplates::EMAIL_INVITATION: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "e-mail Invitation"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_invitation&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_invitation&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs); | ||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||
|                         UInfo.waitingForEmailCheck = true; | ||||
|                     } | ||||
|                     break; | ||||
| @@ -631,43 +519,29 @@ namespace OpenWifi { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) { | ||||
|     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||
|         SecurityObjects::UserInfo   UInfo; | ||||
|  | ||||
|         if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) { | ||||
|             switch (Reason) { | ||||
|  | ||||
|                 case MessagingTemplates::SUB_FORGOT_PASSWORD: { | ||||
|                 case FORGOT_PASSWORD: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "Password reset link"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs); | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|                 case MessagingTemplates::SUB_EMAIL_VERIFICATION: { | ||||
|                 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=sub_email_verification&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs); | ||||
|                     UInfo.waitingForEmailCheck = true; | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|                 case MessagingTemplates::SIGNUP_VERIFICATION: { | ||||
|                     MessageAttributes Attrs; | ||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||
|                     Attrs[LOGO] = GetLogoAssetURI(); | ||||
|                     Attrs[SUBJECT] = "Signup e-mail Address Verification"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ; | ||||
|                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs); | ||||
|                     Attrs[SUBJECT] = "EMail Address Verification"; | ||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||
|                     UInfo.waitingForEmailCheck = true; | ||||
|                 } | ||||
|                 break; | ||||
| @@ -684,14 +558,13 @@ namespace OpenWifi { | ||||
|         SecurityObjects::ActionLink A; | ||||
|  | ||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; | ||||
|         A.userId = UInfo.id; | ||||
|         A.userId = UInfo.email; | ||||
|         A.id = MicroService::CreateUUID(); | ||||
|         A.created = OpenWifi::Now(); | ||||
|         A.created = std::time(nullptr); | ||||
|         A.expires = A.created + 24*60*60; | ||||
|         A.userAction = true; | ||||
|         StorageService()->ActionLinksDB().CreateAction(A); | ||||
|         UInfo.waitingForEmailCheck = true; | ||||
|         UInfo.validated = false; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -699,14 +572,13 @@ namespace OpenWifi { | ||||
|         SecurityObjects::ActionLink A; | ||||
|  | ||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL; | ||||
|         A.userId = UInfo.id; | ||||
|         A.userId = UInfo.email; | ||||
|         A.id = MicroService::CreateUUID(); | ||||
|         A.created = OpenWifi::Now(); | ||||
|         A.created = std::time(nullptr); | ||||
|         A.expires = A.created + 24*60*60; | ||||
|         A.userAction = false; | ||||
|         StorageService()->ActionLinksDB().CreateAction(A); | ||||
|         UInfo.waitingForEmailCheck = true; | ||||
|         UInfo.validated = false; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -721,7 +593,7 @@ namespace OpenWifi { | ||||
|         if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||
|             if(RevocationDate!=0) | ||||
|                 return false; | ||||
|             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); | ||||
|             if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) { | ||||
|                 WebToken = WT; | ||||
|                 return true; | ||||
| @@ -741,7 +613,7 @@ namespace OpenWifi { | ||||
|         if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { | ||||
|             if(RevocationDate!=0) | ||||
|                 return false; | ||||
|             Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now(); | ||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); | ||||
|             if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) { | ||||
|                 WebToken = WT; | ||||
|                 return true; | ||||
|   | ||||
| @@ -22,7 +22,6 @@ | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|  | ||||
| @@ -37,6 +36,11 @@ namespace OpenWifi{ | ||||
|             CUSTOM | ||||
|         }; | ||||
|  | ||||
|         enum EMAIL_REASON { | ||||
|             FORGOT_PASSWORD, | ||||
|             EMAIL_VERIFICATION | ||||
|         }; | ||||
|  | ||||
|         static ACCESS_TYPE IntToAccessType(int C); | ||||
|         static int AccessTypeToInt(ACCESS_TYPE T); | ||||
|  | ||||
| @@ -85,12 +89,10 @@ namespace OpenWifi{ | ||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||
|         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); | ||||
|  | ||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason); | ||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName); | ||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|  | ||||
|         [[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code); | ||||
|  | ||||
|         bool DeleteUserFromCache(const std::string &UserName); | ||||
|         bool DeleteSubUserFromCache(const std::string &UserName); | ||||
|         void RevokeToken(std::string & Token); | ||||
| @@ -110,10 +112,8 @@ namespace OpenWifi{ | ||||
|         inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; } | ||||
|         inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; } | ||||
|  | ||||
|         bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI); | ||||
|         bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI); | ||||
|  | ||||
|     private: | ||||
| 		Poco::JWT::Signer	Signer_; | ||||
| 		Poco::SHA2Engine	SHA2_; | ||||
|  | ||||
| 		std::string         AccessPolicy_; | ||||
| @@ -125,9 +125,8 @@ namespace OpenWifi{ | ||||
|         std::regex          PasswordValidation_; | ||||
|         std::regex          SubPasswordValidation_; | ||||
|  | ||||
|         uint64_t            TokenAging_ = 15 * 24 * 60 * 60; | ||||
|         uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | ||||
|         uint64_t            HowManyOldPassword_=5; | ||||
|         uint64_t            RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ; | ||||
|  | ||||
|         class SHA256Engine : public Poco::Crypto::DigestEngine | ||||
|                 { | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include <cstdlib> | ||||
| #include <boost/algorithm/string.hpp> | ||||
|  | ||||
| #include "Poco/Util/Application.h" | ||||
| #include "Poco/Util/Option.h" | ||||
| @@ -18,7 +20,11 @@ | ||||
| #include "Daemon.h" | ||||
|  | ||||
| #include <aws/core/Aws.h> | ||||
| #include <aws/s3/model/CreateBucketRequest.h> | ||||
| #include <aws/s3/model/PutObjectRequest.h> | ||||
| #include <aws/s3/model/AccessControlPolicy.h> | ||||
| #include <aws/s3/model/PutBucketAclRequest.h> | ||||
| #include <aws/s3/model/GetBucketAclRequest.h> | ||||
|  | ||||
| #include "StorageService.h" | ||||
| #include "SMTPMailerService.h" | ||||
| @@ -50,9 +56,13 @@ namespace OpenWifi { | ||||
|         return instance_; | ||||
|     } | ||||
|  | ||||
|     void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { | ||||
|     void Daemon::initialize() { | ||||
|         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); | ||||
|     } | ||||
|  | ||||
|     void MicroServicePostInitialization() { | ||||
|         Daemon()->initialize(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) { | ||||
|   | ||||
							
								
								
									
										15
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/Daemon.h
									
									
									
									
									
								
							| @@ -24,11 +24,11 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     [[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); | ||||
|     [[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000; | ||||
|     static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties"; | ||||
|     static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT"; | ||||
|     static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG"; | ||||
|     static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str(); | ||||
|     static const uint64_t vDAEMON_BUS_TIMER = 5000; | ||||
|  | ||||
|     class Daemon : public MicroService { | ||||
|     public: | ||||
| @@ -40,7 +40,7 @@ namespace OpenWifi { | ||||
|                         const SubSystemVec & SubSystems) : | ||||
|                 MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; | ||||
|  | ||||
|         void PostInitialization(Poco::Util::Application &self); | ||||
|         void initialize(); | ||||
|         static Daemon *instance(); | ||||
|         inline const std::string & AssetDir() { return AssetDir_; } | ||||
|     private: | ||||
| @@ -49,9 +49,6 @@ namespace OpenWifi { | ||||
|     }; | ||||
|  | ||||
|     inline Daemon * Daemon() { return Daemon::instance(); } | ||||
|     inline void DaemonPostInitialization(Poco::Util::Application &self) { | ||||
|         Daemon()->PostInitialization(self); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #endif //UCENTRALSEC_DAEMON_H | ||||
|   | ||||
| @@ -28,7 +28,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         std::string Challenge = MakeChallenge(); | ||||
|         std::string uuid = MicroService::CreateUUID(); | ||||
|         uint64_t Created = OpenWifi::Now(); | ||||
|         uint64_t Created = std::time(nullptr); | ||||
|  | ||||
|         ChallengeStart.set("uuid",uuid); | ||||
|         ChallengeStart.set("created", Created); | ||||
| @@ -44,7 +44,12 @@ namespace OpenWifi { | ||||
|             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; | ||||
|             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); | ||||
|         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||
|             return AuthService()->SendEmailChallengeCode(UInfo,Challenge); | ||||
|             MessageAttributes Attrs; | ||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||
|             Attrs[SUBJECT] = "Login validation code"; | ||||
|             Attrs[CHALLENGE_CODE] = Challenge; | ||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); | ||||
|         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||
|             return true; | ||||
|         } | ||||
| @@ -60,7 +65,7 @@ namespace OpenWifi { | ||||
|         return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer); | ||||
|     } | ||||
|  | ||||
|     bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||
|     bool MFAServer::CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||
|         std::lock_guard G(Mutex_); | ||||
|  | ||||
|         if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer")) | ||||
| @@ -102,7 +107,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     void MFAServer::CleanCache() { | ||||
|         // it is assumed that you have locked Cache_ at this point. | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||
|             if((Now-i->second.Created)>300) { | ||||
|                 i = Cache_.erase(i); | ||||
|   | ||||
| @@ -2,7 +2,8 @@ | ||||
| // Created by stephane bourque on 2021-10-11. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
| #ifndef OWSEC_MFASERVER_H | ||||
| #define OWSEC_MFASERVER_H | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "Poco/JSON/Object.h" | ||||
| @@ -40,13 +41,15 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); | ||||
|         bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||
|         static bool MethodEnabled(const std::string &Method); | ||||
|         bool ResendCode(const std::string &uuid); | ||||
|         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||
|  | ||||
|         static inline std::string MakeChallenge() { | ||||
|             return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) ); | ||||
|             char buf[16]; | ||||
|             std::sprintf(buf,"%06llu",MicroService::instance().Random(1,999999)); | ||||
|             return buf; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
| @@ -62,3 +65,4 @@ namespace OpenWifi { | ||||
|     inline auto MFAServer() { return MFAServer::instance(); } | ||||
| } | ||||
|  | ||||
| #endif //OWSEC_MFASERVER_H | ||||
|   | ||||
| @@ -1,8 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-07-25. | ||||
| // | ||||
|  | ||||
| #include "MessagingTemplates.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| } // OpenWifi | ||||
| @@ -1,75 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-07-25. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class MessagingTemplates { | ||||
|     public: | ||||
|         static MessagingTemplates & instance() { | ||||
|             static auto instance = new MessagingTemplates; | ||||
|             return *instance; | ||||
|         } | ||||
|  | ||||
|         enum EMAIL_REASON { | ||||
|             FORGOT_PASSWORD = 0, | ||||
|             EMAIL_VERIFICATION, | ||||
|             SIGNUP_VERIFICATION, | ||||
|             EMAIL_INVITATION, | ||||
|             VERIFICATION_CODE, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_EMAIL_VERIFICATION, | ||||
|             SUB_VERIFICATION_CODE | ||||
|         }; | ||||
|  | ||||
|         static std::string AddOperator(const std::string & filename, const std::string &OperatorName) { | ||||
|             if(OperatorName.empty()) | ||||
|                 return "/" + filename; | ||||
|             return "/" + OperatorName + "/" + filename; | ||||
|         } | ||||
|  | ||||
|         static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") { | ||||
|             switch (r) { | ||||
|                 case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName); | ||||
|                 case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName); | ||||
|                 case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName); | ||||
|                 case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName); | ||||
|                 case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName); | ||||
|                 case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName); | ||||
|                 case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName); | ||||
|                 case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName); | ||||
|                 default: | ||||
|                     return ""; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         static std::string Logo(const std::string &OperatorName = "" ) { | ||||
|             return AddOperator("logo.jpg", OperatorName); | ||||
|         } | ||||
|  | ||||
|         static std::string SubLogo(const std::string &OperatorName = "" ) { | ||||
|             return AddOperator("sub_logo.jpg", OperatorName); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         inline const static std::vector<std::string>  EmailTemplateNames = { | ||||
|                 "password_reset", | ||||
|                 "email_verification", | ||||
|                 "signup_verification", | ||||
|                 "email_invitation", | ||||
|                 "verification_code", | ||||
|                 "sub_password_reset", | ||||
|                 "sub_email_verification", | ||||
|                 "sub_verification_code" | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); } | ||||
|  | ||||
| } // OpenWifi | ||||
|  | ||||
| @@ -23,14 +23,8 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(Action=="password_reset") | ||||
|             return RequestResetPassword(Link); | ||||
|         else if(Action=="sub_password_reset") | ||||
|             return RequestSubResetPassword(Link); | ||||
|         else if(Action=="email_verification") | ||||
|             return DoEmailVerification(Link); | ||||
|         else if(Action=="sub_email_verification") | ||||
|             return DoSubEmailVerification(Link); | ||||
|         else if(Action=="signup_verification") | ||||
|             return DoNewSubVerification(Link); | ||||
|         else | ||||
|             return DoReturnA404(); | ||||
|     } | ||||
| @@ -40,32 +34,18 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(Action=="password_reset") | ||||
|             return CompleteResetPassword(); | ||||
|         else if(Action=="sub_password_reset") | ||||
|             return CompleteResetPassword(); | ||||
|         else if(Action=="signup_completion") | ||||
|             return CompleteSubVerification(); | ||||
|         else if(Action=="email_invitation") | ||||
|             return CompleteEmailInvitation(); | ||||
|         else | ||||
|             return DoReturnA404(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) { | ||||
|         Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId)); | ||||
|         Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId)); | ||||
|         Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; | ||||
|         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||
|         SendHTMLFileBack(FormFile,FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) { | ||||
|         Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId)); | ||||
|         Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification.html"}; | ||||
|         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||
|         SendHTMLFileBack(FormFile,FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::CompleteResetPassword() { | ||||
|         //  form has been posted... | ||||
|         RESTAPI_PartHandler PartHandler; | ||||
| @@ -73,15 +53,15 @@ namespace OpenWifi { | ||||
|         if (!Form.empty()) { | ||||
|  | ||||
|             auto Password1 = Form.get("password1","bla"); | ||||
|             auto Password2 = Form.get("password2","blu"); | ||||
|             auto Password2 = Form.get("password1","blu"); | ||||
|             auto Id = Form.get("id",""); | ||||
|             auto now = OpenWifi::Now(); | ||||
|             auto Now = std::time(nullptr); | ||||
|  | ||||
|             SecurityObjects::ActionLink Link; | ||||
|             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) | ||||
|                 return DoReturnA404(); | ||||
|  | ||||
|             if(now > Link.expires) { | ||||
|             if(Now > Link.expires) { | ||||
|                 StorageService()->ActionLinksDB().CancelAction(Id); | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
| @@ -121,7 +101,7 @@ namespace OpenWifi { | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             UInfo.modified = OpenWifi::Now(); | ||||
|             UInfo.modified = std::time(nullptr); | ||||
|             if(Link.userAction) | ||||
|                 StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||
|             else | ||||
| @@ -138,102 +118,10 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::CompleteSubVerification() { | ||||
|         RESTAPI_PartHandler PartHandler; | ||||
|         Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); | ||||
|  | ||||
|         if (!Form.empty()) { | ||||
|             auto Password1 = Form.get("password1","bla"); | ||||
|             auto Password2 = Form.get("password2","blu"); | ||||
|             auto Id = Form.get("id",""); | ||||
|             auto now = OpenWifi::Now(); | ||||
|  | ||||
|             SecurityObjects::ActionLink Link; | ||||
|             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) { | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
|  | ||||
|             if(now > Link.expires) { | ||||
|                 StorageService()->ActionLinksDB().CancelAction(Id); | ||||
|                 return DoReturnA404(); | ||||
|             } | ||||
|  | ||||
|             if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with" | ||||
|                                                                  " accepted password creation restrictions. Please consult our on-line help" | ||||
|                                                                  " to look at the our password policy. If you would like to contact us, please mention" | ||||
|                                                                  " id(" + Id + ")"}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             SecurityObjects::UserInfo   UInfo; | ||||
|             bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo); | ||||
|             if(!Found) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             if(UInfo.blackListed || UInfo.suspended) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo); | ||||
|             if(!GoodPassword) { | ||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"}; | ||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; | ||||
|                 return SendHTMLFileBack(FormFile,FormVars); | ||||
|             } | ||||
|  | ||||
|             UInfo.modified = OpenWifi::Now(); | ||||
|             UInfo.changePassword = false; | ||||
|             UInfo.lastEmailCheck = OpenWifi::Now(); | ||||
|             UInfo.waitingForEmailCheck = false; | ||||
|             UInfo.validated = OpenWifi::Now(); | ||||
|  | ||||
|             StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||
|  | ||||
|             Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"}; | ||||
|             Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||
|                                               {"USERNAME", UInfo.email} }; | ||||
|             StorageService()->ActionLinksDB().CompleteAction(Id); | ||||
|  | ||||
|             //  Send the update to the provisioning service | ||||
|             Poco::JSON::Object  Body; | ||||
|             auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||
|             Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]); | ||||
|             OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup", | ||||
|                                             { | ||||
|                                                 {"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} , | ||||
|                                                 {"operation", "emailVerified"} | ||||
|                                             }, | ||||
|                                             Body,30000); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email)); | ||||
|             Poco::JSON::Object::Ptr Response; | ||||
|             auto Status = ProvRequest.Do(Response); | ||||
|             std::stringstream ooo; | ||||
|             if(Response!= nullptr) | ||||
|                 Response->stringify(ooo); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.", | ||||
|                                              UInfo.email, Status)); | ||||
|             SendHTMLFileBack(FormFile,FormVars); | ||||
|             Logger().information(fmt::format("({}): Completed subscriber e-mail verification. FORM notified.",UInfo.email)); | ||||
|         } else { | ||||
|             DoReturnA404(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) { | ||||
|         auto now = OpenWifi::Now(); | ||||
|         auto Now = std::time(nullptr); | ||||
|  | ||||
|         if(now > Link.expires) { | ||||
|         if(Now > Link.expires) { | ||||
|             StorageService()->ActionLinksDB().CancelAction(Link.id); | ||||
|             return DoReturnA404(); | ||||
|         } | ||||
| @@ -247,13 +135,12 @@ namespace OpenWifi { | ||||
|             return SendHTMLFileBack(FormFile, FormVars); | ||||
|         } | ||||
|  | ||||
|         Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(), | ||||
|                                         UInfo.email)); | ||||
|         Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email)); | ||||
|         UInfo.waitingForEmailCheck = false; | ||||
|         UInfo.validated = true; | ||||
|         UInfo.lastEmailCheck = OpenWifi::Now(); | ||||
|         UInfo.validationDate = OpenWifi::Now(); | ||||
|         UInfo.modified  = OpenWifi::Now(); | ||||
|         UInfo.lastEmailCheck = std::time(nullptr); | ||||
|         UInfo.validationDate = std::time(nullptr); | ||||
|         UInfo.modified  = std::time(nullptr); | ||||
|         if(Link.userAction) | ||||
|             StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||
|         else | ||||
| @@ -272,16 +159,4 @@ namespace OpenWifi { | ||||
|         SendHTMLFileBack(FormFile, FormVars); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::CompleteEmailInvitation() { | ||||
|         /// TODO: | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -20,16 +20,11 @@ namespace OpenWifi { | ||||
|                                         Internal, | ||||
|                                         false, | ||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; | ||||
|         void RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||
|         void RequestSubResetPassword(SecurityObjects::ActionLink &Link); | ||||
|         void CompleteResetPassword(); | ||||
|         void CompleteSubVerification(); | ||||
|         void DoEmailVerification(SecurityObjects::ActionLink &Link); | ||||
|         void DoSubEmailVerification(SecurityObjects::ActionLink &Link); | ||||
|         void DoReturnA404(); | ||||
|         void DoNewSubVerification(SecurityObjects::ActionLink &Link); | ||||
|         void CompleteEmailInvitation(); | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  | ||||
| #include "RESTAPI_asset_server.h" | ||||
| #include "Poco/File.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "Daemon.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal, false) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" , | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" , | ||||
|                                                                                          "/favicon.ico"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "RESTAPI_avatar_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "Poco/Net/HTMLForm.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| @@ -37,11 +38,10 @@ namespace OpenWifi { | ||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); | ||||
|             Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType())); | ||||
|             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); | ||||
|             StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, | ||||
|                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); | ||||
|             StorageService()->UserDB().SetAvatar(Id,"1"); | ||||
|             Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email)); | ||||
|         } else { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||
| @@ -60,7 +60,6 @@ namespace OpenWifi { | ||||
|         if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size())); | ||||
|         return SendFileContent(AvatarContent, Type, Name); | ||||
|     } | ||||
|  | ||||
| @@ -68,14 +67,13 @@ namespace OpenWifi { | ||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
|  | ||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
|         Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email)); | ||||
|         StorageService()->UserDB().SetAvatar(Id,""); | ||||
|         OK(); | ||||
|     } | ||||
|   | ||||
| @@ -26,8 +26,6 @@ namespace OpenWifi { | ||||
|         std::string     Id_; | ||||
|         Poco::Logger    &Logger_; | ||||
|         std::stringstream &OutputStream_; | ||||
|  | ||||
|         inline Poco::Logger & Logger() { return Logger_; }; | ||||
|     }; | ||||
|  | ||||
|     class RESTAPI_avatar_handler : public RESTAPIHandler { | ||||
| @@ -42,7 +40,7 @@ namespace OpenWifi { | ||||
|                                          Server, | ||||
|                                          TransactionId, | ||||
|                                          Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/avatar/{id}"}; }; | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) { | ||||
|     inline void Sanitize(const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) { | ||||
|         U.currentPassword.clear(); | ||||
|         U.lastPasswords.clear(); | ||||
|         U.oauthType.clear(); | ||||
|   | ||||
| @@ -9,12 +9,12 @@ | ||||
| #include "Poco/JSON/Parser.h" | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     void RESTAPI_email_handler::DoPost() { | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         auto Obj = ParseStream(); | ||||
|         if (Obj->has("subject") && | ||||
|             Obj->has("from") && | ||||
|             Obj->has("text") && | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                   Server, | ||||
|                                                   TransactionId, | ||||
|                                                   Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/email"};} | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};} | ||||
|         void DoGet() final {}; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI_oauth2_handler.h" | ||||
| #include "MFAServer.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| @@ -22,12 +22,12 @@ namespace OpenWifi { | ||||
| 	    bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|         } | ||||
|         if (GetBoolParameter(RESTAPI::Protocol::ME)) { | ||||
|             Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(), | ||||
|                                             UserInfo_.userinfo.email)); | ||||
|         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; | ||||
|             Sanitize(UserInfo_, ReturnedUser); | ||||
| @@ -38,52 +38,33 @@ namespace OpenWifi { | ||||
| 	} | ||||
|  | ||||
|     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); | ||||
| 	    bool Expired = false, Contacted=false; | ||||
| 	    if (!IsAuthorized(Expired, Contacted)) { | ||||
| 	        if(Expired) | ||||
| 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
| 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
| 	    } | ||||
|  | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||
|         if (Token == SessionToken_) { | ||||
|             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); | ||||
|         Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||
|         NotFound(); | ||||
| 	} | ||||
|  | ||||
| 	void RESTAPI_oauth2_handler::DoPost() { | ||||
|         auto Obj = ParseStream(); | ||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); | ||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); | ||||
|         auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj); | ||||
|         auto refreshToken = GetS("refreshToken", Obj); | ||||
|         auto grant_type = GetParameter("grant_type"); | ||||
|  | ||||
|         Poco::toLowerInPlace(userId); | ||||
|  | ||||
|         if(!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())); | ||||
|         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, AuthService()->GetAccessPolicy()); | ||||
| @@ -91,17 +72,17 @@ namespace OpenWifi { | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||
|             SecurityObjects::UserInfo UInfo1; | ||||
|             auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1); | ||||
|             if(UserExists) { | ||||
|                 Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|                 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 = OpenWifi::Now(); | ||||
|                 NewLink.created = std::time(nullptr); | ||||
|                 NewLink.expires = NewLink.created + (24*60*60); | ||||
|                 NewLink.userAction = true; | ||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
| @@ -120,18 +101,18 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) { | ||||
|             Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|         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::BAD_MFA_TRANSACTION); | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||
|             Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|             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)) { | ||||
| @@ -140,7 +121,7 @@ namespace OpenWifi { | ||||
|                     return ReturnObject(ReturnObj); | ||||
|                 } | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfoAndPolicy UInfo; | ||||
| @@ -160,17 +141,17 @@ namespace OpenWifi { | ||||
|  | ||||
|             switch(Code) { | ||||
|                 case INVALID_CREDENTIALS: | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); | ||||
|                 case PASSWORD_INVALID: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); | ||||
|                 case PASSWORD_ALREADY_USED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); | ||||
|                 case USERNAME_PENDING_VERIFICATION: | ||||
|                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); | ||||
|                 case PASSWORD_CHANGE_REQUIRED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); | ||||
|                 default: | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ namespace OpenWifi { | ||||
| 													  Server, | ||||
|                                                       TransactionId, | ||||
| 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||
| 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoDelete() final; | ||||
|   | ||||
| @@ -19,13 +19,13 @@ namespace OpenWifi { | ||||
|  | ||||
|         SecurityObjects::Preferences    P; | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         auto RawObject = ParseStream(); | ||||
|         if(!P.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         P.id = UserInfo_.userinfo.id; | ||||
|         P.modified = OpenWifi::Now(); | ||||
|         P.modified = std::time(nullptr); | ||||
|         StorageService()->PreferencesDB().SetPreferences(P); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; }; | ||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/preferences"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPut() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -24,17 +24,15 @@ | ||||
| #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) { | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const char *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_user_handler, | ||||
|             RESTAPI_system_command, | ||||
|             RESTAPI_asset_server, | ||||
|             RESTAPI_system_endpoints_handler, | ||||
| @@ -50,39 +48,26 @@ namespace OpenWifi { | ||||
|             RESTAPI_subusers_handler, | ||||
|             RESTAPI_submfa_handler, | ||||
|             RESTAPI_totp_handler, | ||||
|             RESTAPI_subtotp_handler, | ||||
|             RESTAPI_signup_handler, | ||||
|             RESTAPI_validate_sub_token_handler, | ||||
|             RESTAPI_validate_token_handler | ||||
|             RESTAPI_subtotp_handler | ||||
|         >(Path, Bindings, L, S,TransactionId); | ||||
|     } | ||||
|  | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, | ||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const char *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_user_handler, | ||||
|             RESTAPI_subuser_handler, | ||||
|             RESTAPI_subusers_handler, | ||||
|             RESTAPI_system_command, | ||||
|             RESTAPI_asset_server, | ||||
|             RESTAPI_system_endpoints_handler, | ||||
|             RESTAPI_action_links, | ||||
|             RESTAPI_avatar_handler, | ||||
|             RESTAPI_subavatar_handler, | ||||
|             RESTAPI_email_handler, | ||||
|             RESTAPI_validate_token_handler, | ||||
|             RESTAPI_validate_sub_token_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 | ||||
|             RESTAPI_submfa_handler | ||||
|         >(Path, Bindings, L, S, TransactionId); | ||||
|     } | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-02-20. | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_signup_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| #define __DBG__ std::cout << __LINE__ << std::endl; | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_signup_handler::DoPost() { | ||||
|         auto UserName = GetParameter("email"); | ||||
|         auto signupUUID = GetParameter("signupUUID"); | ||||
|         auto owner = GetParameter("owner"); | ||||
|         auto operatorName = GetParameter("operatorName"); | ||||
|         if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) { | ||||
|             Logger().error("Signup requires: email, signupUUID, operatorName, and owner."); | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
|  | ||||
|         if(!Utils::ValidEMailAddress(UserName)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||
|         } | ||||
|  | ||||
|         // Do we already exist? Can only signup once... | ||||
|         SecurityObjects::UserInfo   Existing; | ||||
|         if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) { | ||||
|             if(Existing.signingUp.empty()) { | ||||
|                 return BadRequest(RESTAPI::Errors::SignupAlreadySigned); | ||||
|             } | ||||
|  | ||||
|             if(Existing.waitingForEmailCheck) { | ||||
|                 return BadRequest(RESTAPI::Errors::SignupEmailCheck); | ||||
|             } | ||||
|  | ||||
|             return BadRequest(RESTAPI::Errors::SignupWaitingForDevice); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewSub; | ||||
|         NewSub.signingUp = operatorName + ":" + signupUUID; | ||||
|         NewSub.waitingForEmailCheck = true; | ||||
|         NewSub.name = UserName; | ||||
|         NewSub.modified = OpenWifi::Now(); | ||||
|         NewSub.creationDate = OpenWifi::Now(); | ||||
|         NewSub.id = MicroService::instance().CreateUUID(); | ||||
|         NewSub.email = UserName; | ||||
|         NewSub.userRole = SecurityObjects::SUBSCRIBER; | ||||
|         NewSub.changePassword = true; | ||||
|         NewSub.owner = owner; | ||||
|  | ||||
|         StorageService()->SubDB().CreateRecord(NewSub); | ||||
|  | ||||
|         Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName)); | ||||
|         SecurityObjects::ActionLink NewLink; | ||||
|  | ||||
|         NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP; | ||||
|         NewLink.id = MicroService::CreateUUID(); | ||||
|         NewLink.userId = NewSub.id; | ||||
|         NewLink.created = OpenWifi::Now(); | ||||
|         NewLink.expires = NewLink.created + (1*60*60);  // 1 hour | ||||
|         NewLink.userAction = false; | ||||
|         StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|         NewSub.to_json(Answer); | ||||
|         return ReturnObject(Answer); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_signup_handler::DoPut() { | ||||
|         // TODO | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| // | ||||
| // 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,17 +4,13 @@ | ||||
|  | ||||
| #include "RESTAPI_sms_handler.h" | ||||
| #include "SMSSender.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void OpenWifi::RESTAPI_sms_handler::DoPost() { | ||||
|         const auto &Obj = ParsedBody_; | ||||
|  | ||||
|         if(!SMSSender()->Enabled()) { | ||||
|             return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|         } | ||||
|         auto Obj = ParseStream(); | ||||
|  | ||||
|         std::string Arg; | ||||
|         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { | ||||
| @@ -40,7 +36,7 @@ namespace OpenWifi { | ||||
|         if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && | ||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER && | ||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights,ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (Obj->has("to") && | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                   Server, | ||||
|                                                   TransactionId, | ||||
|                                                   Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/sms"};} | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};} | ||||
|         void DoGet() final {}; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "RESTAPI_subavatar_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "Poco/Net/HTMLForm.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| @@ -37,11 +38,10 @@ namespace OpenWifi { | ||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); | ||||
|             Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType())); | ||||
|             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); | ||||
|             StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email, | ||||
|                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); | ||||
|             StorageService()->SubDB().SetAvatar(Id,"1"); | ||||
|             Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email)); | ||||
|         } else { | ||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||
| @@ -60,7 +60,6 @@ namespace OpenWifi { | ||||
|         if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Retrieving avatar for {}",UserInfo_.userinfo.email)); | ||||
|         return SendFileContent(AvatarContent, Type, Name); | ||||
|     } | ||||
|  | ||||
| @@ -68,13 +67,12 @@ namespace OpenWifi { | ||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
|  | ||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email)); | ||||
|         StorageService()->SubDB().SetAvatar(Id,""); | ||||
|         OK(); | ||||
|     } | ||||
|   | ||||
| @@ -26,8 +26,6 @@ namespace OpenWifi { | ||||
|         std::string     Id_; | ||||
|         Poco::Logger    &Logger_; | ||||
|         std::stringstream &OutputStream_; | ||||
|  | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
|  | ||||
|     class RESTAPI_subavatar_handler : public RESTAPIHandler { | ||||
| @@ -42,7 +40,7 @@ namespace OpenWifi { | ||||
|                                          Server, | ||||
|                                          TransactionId, | ||||
|                                          Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subavatar/{id}"}; }; | ||||
|  | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|   | ||||
| @@ -11,6 +11,7 @@ namespace OpenWifi { | ||||
|     void RESTAPI_submfa_handler::DoGet() { | ||||
|         SecurityObjects::UserInfo   User; | ||||
|  | ||||
|         // std::cout << "submfa get " << UserInfo_.userinfo.Id << "   user:" << UserInfo_.userinfo.email << std::endl; | ||||
|         if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) { | ||||
|             Poco::JSON::Object              Answer; | ||||
|             SecurityObjects::SubMfaConfig   MFC; | ||||
| @@ -36,7 +37,7 @@ namespace OpenWifi { | ||||
|     void RESTAPI_submfa_handler::DoPut() { | ||||
|  | ||||
|         try { | ||||
|             const auto & Body = ParsedBody_; | ||||
|             auto Body = ParseStream(); | ||||
|  | ||||
|             SecurityObjects::SubMfaConfig MFC; | ||||
|  | ||||
| @@ -73,30 +74,21 @@ namespace OpenWifi { | ||||
|             } 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); | ||||
|                         return BadRequest("Missing phone number"); | ||||
|                     } | ||||
|  | ||||
|                     if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) { | ||||
|                         return OK(); | ||||
|                     } else { | ||||
|                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); | ||||
|                     } | ||||
|                 } 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); | ||||
|                         return BadRequest("Missing 'challengeCode'"); | ||||
|                     } | ||||
|                     if (MFC.sms.empty()) { | ||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); | ||||
|                         return BadRequest("Missing phone number"); | ||||
|                     } | ||||
|                     if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) { | ||||
|                         SecurityObjects::UserInfo User; | ||||
| @@ -124,7 +116,7 @@ namespace OpenWifi { | ||||
|                         return ReturnObject(Answer); | ||||
|  | ||||
|                     } else { | ||||
|                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                                   TransactionId, | ||||
|                                                   Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10}, | ||||
|                                                   true) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; }; | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/submfa"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "RESTAPI_suboauth2_handler.h" | ||||
| #include "AuthService.h" | ||||
| #include "MFAServer.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -15,12 +16,12 @@ namespace OpenWifi { | ||||
|         bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted, true)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|         } | ||||
|         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||
|         if(GetMe) { | ||||
|             Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(), | ||||
|             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; | ||||
| @@ -32,46 +33,33 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     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); | ||||
|         bool Expired = false, Contacted = false; | ||||
|         if (!IsAuthorized(Expired, Contacted, true)) { | ||||
|             if(Expired) | ||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | ||||
|         } | ||||
|  | ||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||
|         if (Token == SessionToken_) { | ||||
|             AuthService()->SubLogout(Token); | ||||
|             return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); | ||||
|         } | ||||
|  | ||||
|         Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||
|         NotFound(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_suboauth2_handler::DoPost() { | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         auto Obj = ParseStream(); | ||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); | ||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); | ||||
|         auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj); | ||||
|         auto refreshToken = GetS("refreshToken", Obj); | ||||
|         auto grant_type = GetParameter("grant_type"); | ||||
|  | ||||
|         Poco::toLowerInPlace(userId); | ||||
|  | ||||
|         if(!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())); | ||||
|         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()->SubPasswordValidationExpression()); | ||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy()); | ||||
| @@ -79,17 +67,17 @@ namespace OpenWifi { | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) { | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||
|             SecurityObjects::UserInfo UInfo1; | ||||
|             auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1); | ||||
|             if(UserExists) { | ||||
|                 Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", 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.created = std::time(nullptr); | ||||
|                 NewLink.expires = NewLink.created + (24*60*60); | ||||
|                 NewLink.userAction = false; | ||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); | ||||
| @@ -108,18 +96,18 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) { | ||||
|             Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|         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::BAD_MFA_TRANSACTION); | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) { | ||||
|             Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId)); | ||||
|         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") && Obj->has("answer")) { | ||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||
|                 if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) { | ||||
| @@ -128,7 +116,7 @@ namespace OpenWifi { | ||||
|                     return ReturnObject(ReturnObj); | ||||
|                 } | ||||
|             } | ||||
|             return UnAuthorized(RESTAPI::Errors::MFA_FAILURE); | ||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfoAndPolicy UInfo; | ||||
| @@ -147,17 +135,17 @@ namespace OpenWifi { | ||||
|         } else { | ||||
|             switch(Code) { | ||||
|                 case INVALID_CREDENTIALS: | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); | ||||
|                 case PASSWORD_INVALID: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); | ||||
|                 case PASSWORD_ALREADY_USED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); | ||||
|                 case USERNAME_PENDING_VERIFICATION: | ||||
|                     return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION); | ||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); | ||||
|                 case PASSWORD_CHANGE_REQUIRED: | ||||
|                     return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); | ||||
|                 default: | ||||
|                     return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break; | ||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                                   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"}; }; | ||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -19,13 +19,13 @@ namespace OpenWifi { | ||||
|  | ||||
|         SecurityObjects::Preferences    P; | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         auto RawObject = ParseStream(); | ||||
|         if(!P.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         P.id = UserInfo_.userinfo.id; | ||||
|         P.modified = OpenWifi::Now(); | ||||
|         P.modified = std::time(nullptr); | ||||
|         StorageService()->SubPreferencesDB().SetPreferences(P); | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; }; | ||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subpreferences"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPut() final; | ||||
|         void DoPost() final {}; | ||||
|   | ||||
| @@ -24,14 +24,15 @@ namespace OpenWifi { | ||||
|         auto nextIndex = GetParameter("index",0); | ||||
|         bool moreCodes=false; | ||||
|  | ||||
|         RESTAPI::Errors::msg    Error; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) { | ||||
|         uint64_t ErrorCode = 0; | ||||
|         std::string ErrorText; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, ErrorCode, ErrorText )) { | ||||
|             Poco::JSON::Object Answer; | ||||
|             Answer.set("nextIndex", nextIndex); | ||||
|             Answer.set("moreCodes", moreCodes); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         return BadRequest(Error); | ||||
|         return BadRequest(ErrorCode, ErrorText); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|                                  Server, | ||||
|                                  TransactionId, | ||||
|                                  Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subtotp"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -4,9 +4,8 @@ | ||||
|  | ||||
| #include "RESTAPI_subuser_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "SMSSender.h" | ||||
| #include "SMTPMailerService.h" | ||||
| #include "ACLProcessor.h" | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -53,8 +52,8 @@ namespace OpenWifi { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|         } | ||||
|  | ||||
|         if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||
| @@ -65,7 +64,7 @@ namespace OpenWifi { | ||||
|         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)); | ||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||
|         OK(); | ||||
|     } | ||||
|  | ||||
| @@ -76,23 +75,13 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         RESTAPI_utils::from_request(NewUser,*Request); | ||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|         } | ||||
|  | ||||
|         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); | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::toLowerInPlace(NewUser.email); | ||||
| @@ -115,19 +104,19 @@ namespace OpenWifi { | ||||
|         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)); | ||||
|         if(!StorageService()->SubDB().CreateUser(NewUser.email, NewUser)) { | ||||
|             Logger_.information(Poco::format("Could not add user '%s'.",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)); | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",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)); | ||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
| @@ -135,7 +124,7 @@ namespace OpenWifi { | ||||
|         Sanitize(UserInfo_, NewUser); | ||||
|         NewUser.to_json(UserInfoObject); | ||||
|         ReturnObject(UserInfoObject); | ||||
|         Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_subuser_handler::DoPut() { | ||||
| @@ -149,52 +138,12 @@ namespace OpenWifi { | ||||
|             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(); | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         auto RawObject = ParseStream(); | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| @@ -220,10 +169,10 @@ namespace OpenWifi { | ||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||
|             if(NewRole!=Existing.userRole) { | ||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                 } | ||||
|                 if(Id==UserInfo_.userinfo.id) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                 } | ||||
|                 Existing.userRole = NewRole; | ||||
|             } | ||||
| @@ -233,7 +182,7 @@ namespace OpenWifi { | ||||
|             SecurityObjects::NoteInfoVec NIV; | ||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||
|             for(auto const &i:NIV) { | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 Existing.notes.push_back(ii); | ||||
|             } | ||||
|         } | ||||
| @@ -248,7 +197,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|             if(AuthService::VerifySubEmail(Existing)) | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email)); | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email)); | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("userTypeProprietaryInfo")) { | ||||
| @@ -257,32 +206,23 @@ namespace OpenWifi { | ||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||
|                 } | ||||
|  | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||
|                     !SMSSender()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                 } | ||||
|                 bool ChangingMFA = | ||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||
|  | ||||
|                 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); | ||||
|                     } | ||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||
|                     if (PInfo->isArray("mobiles")) { | ||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles[0].verified = true; | ||||
|                     } | ||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || | ||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, | ||||
|                                                     UserInfo_.userinfo.email)) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                     std::string Secret; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||
| @@ -292,10 +232,13 @@ namespace OpenWifi { | ||||
|                     } else { | ||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||
|                     } | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     // nothing to do for email. | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|             } else { | ||||
|                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; }; | ||||
|                           static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subuser/{id}"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -4,77 +4,52 @@ | ||||
|  | ||||
| #include "RESTAPI_subusers_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_subusers_handler::DoGet() { | ||||
|         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); | ||||
|                 } | ||||
|             } | ||||
|         std::vector<SecurityObjects::UserInfo> Users; | ||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); | ||||
|  | ||||
|         if(QB_.Select.empty()) { | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             Poco::JSON::Object Answer; | ||||
|             if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||
|                 for (auto &i : Users) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                 Poco::JSON::Array   Arr; | ||||
|                 Poco::JSON::Object  Answer; | ||||
|  | ||||
|                 for(const auto &i:Users.users) { | ||||
|                     Arr.add(i.id); | ||||
|                         ArrayObj.add(i.id); | ||||
|                     } else { | ||||
|                         Sanitize(UserInfo_, i); | ||||
|                         i.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     } | ||||
|                 Answer.set("users",Arr); | ||||
|                 return ReturnObject(Answer); | ||||
|                 } | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Users.to_json(Answer); | ||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             } | ||||
|             return ReturnObject(Answer); | ||||
|         } else { | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             for(auto &i:SelectedRecords()) { | ||||
|                 SecurityObjects::UserInfo   UInfo; | ||||
|                 if(StorageService()->SubDB().GetUserById(i,UInfo)) { | ||||
|                 auto tI{i}; | ||||
|                 if(StorageService()->SubDB().GetUserById(tI,UInfo)) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(UInfo.id); | ||||
|                     } else { | ||||
|                         Sanitize(UserInfo_, UInfo); | ||||
|                     Users.users.emplace_back(UInfo); | ||||
|                 } | ||||
|             } | ||||
|             Poco::JSON::Object Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|                         UInfo.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Poco::JSON::Object RetObj; | ||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             return ReturnObject(RetObj); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/subusers"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subusers"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ namespace OpenWifi { | ||||
|                                                           Server, | ||||
|                                                           TransactionId, | ||||
|                                                           Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/systemEndpoints"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/systemEndpoints"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -11,6 +11,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         auto Reset = GetBoolParameter("reset",false); | ||||
|         std::string QRCode; | ||||
|  | ||||
|         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { | ||||
|             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); | ||||
|         } | ||||
| @@ -22,14 +23,15 @@ namespace OpenWifi { | ||||
|         auto nextIndex = GetParameter("index",0); | ||||
|         bool moreCodes=false; | ||||
|  | ||||
|         RESTAPI::Errors::msg Err; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,false,Value,nextIndex,moreCodes, Err)) { | ||||
|         uint64_t ErrorCode = 0; | ||||
|         std::string ErrorText; | ||||
|         if(TotpCache()->ContinueValidation(UserInfo_.userinfo,false,Value,nextIndex,moreCodes, ErrorCode, ErrorText )) { | ||||
|             Poco::JSON::Object Answer; | ||||
|             Answer.set("nextIndex", nextIndex); | ||||
|             Answer.set("moreCodes", moreCodes); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         return BadRequest(Err); | ||||
|         return BadRequest(ErrorCode, ErrorText); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                  Server, | ||||
|                                  TransactionId, | ||||
|                                  Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/totp"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/totp"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -4,9 +4,8 @@ | ||||
|  | ||||
| #include "RESTAPI_user_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/RESTAPI_errors.h" | ||||
| #include "SMSSender.h" | ||||
| #include "SMTPMailerService.h" | ||||
| #include "ACLProcessor.h" | ||||
| #include "AuthService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| @@ -33,7 +32,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::JSON::Object  UserInfoObject; | ||||
| @@ -54,7 +53,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||
| @@ -65,23 +64,18 @@ namespace OpenWifi { | ||||
|         StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||
|         StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id); | ||||
|         StorageService()->UserTokenDB().RevokeAllTokens(Id); | ||||
|         Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email)); | ||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||
|         OK(); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_user_handler::DoPost() { | ||||
|  | ||||
|         std::string Id = GetBinding("id", ""); | ||||
|         if(Id!="0") { | ||||
|             return BadRequest(RESTAPI::Errors::IdMustBe0); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         RESTAPI_utils::from_request(NewUser,*Request); | ||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||
|         } | ||||
| @@ -93,7 +87,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||
|             return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         Poco::toLowerInPlace(NewUser.email); | ||||
| @@ -101,11 +95,6 @@ namespace OpenWifi { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   Existing; | ||||
|         if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) { | ||||
|             return BadRequest(RESTAPI::Errors::UserAlreadyExists); | ||||
|         } | ||||
|  | ||||
|         if(!NewUser.currentPassword.empty()) { | ||||
|             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { | ||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||
| @@ -120,21 +109,20 @@ namespace OpenWifi { | ||||
|         NewUser.userTypeProprietaryInfo.mfa.method = ""; | ||||
|         NewUser.userTypeProprietaryInfo.mobiles.clear(); | ||||
|         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|         NewUser.validated = true; | ||||
|  | ||||
|         if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) { | ||||
|             Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email)); | ||||
|             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); | ||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("email_verification")) { | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|             if(AuthService::VerifyEmail(NewUser)) | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email)); | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); | ||||
|             StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser); | ||||
|         } | ||||
|  | ||||
|         if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) { | ||||
|             Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email)); | ||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
| @@ -142,11 +130,10 @@ namespace OpenWifi { | ||||
|         Sanitize(UserInfo_, NewUser); | ||||
|         NewUser.to_json(UserInfoObject); | ||||
|         ReturnObject(UserInfoObject); | ||||
|         Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_user_handler::DoPut() { | ||||
|  | ||||
|         std::string Id = GetBinding("id", ""); | ||||
|         if(Id.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); | ||||
| @@ -158,50 +145,11 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         if(!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()->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(); | ||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||
|         } | ||||
|  | ||||
|         SecurityObjects::UserInfo   NewUser; | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         auto RawObject = ParseStream(); | ||||
|         if(!NewUser.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| @@ -230,10 +178,10 @@ namespace OpenWifi { | ||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||
|             if(NewRole!=Existing.userRole) { | ||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                 } | ||||
|                 if(Id==UserInfo_.userinfo.id) { | ||||
|                     return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); | ||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||
|                 } | ||||
|                 Existing.userRole = NewRole; | ||||
|             } | ||||
| @@ -243,7 +191,7 @@ namespace OpenWifi { | ||||
|             SecurityObjects::NoteInfoVec NIV; | ||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||
|             for(auto const &i:NIV) { | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note}; | ||||
|                 Existing.notes.push_back(ii); | ||||
|             } | ||||
|         } | ||||
| @@ -256,9 +204,9 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(GetBoolParameter("email_verification")) { | ||||
|         if(GetParameter("email_verification","false")=="true") { | ||||
|             if(AuthService::VerifyEmail(Existing)) | ||||
|                 Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email)); | ||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email)); | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("userTypeProprietaryInfo")) { | ||||
| @@ -267,32 +215,23 @@ namespace OpenWifi { | ||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); | ||||
|                 } | ||||
|  | ||||
|                 if( NewUser.userTypeProprietaryInfo.mfa.enabled && | ||||
|                     NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS && | ||||
|                     !SMSSender()->Enabled()) { | ||||
|                     return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||
|                 } | ||||
|                 bool ChangingMFA = | ||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||
|  | ||||
|                 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); | ||||
|                     } | ||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { | ||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||
|                     if (PInfo->isArray("mobiles")) { | ||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles[0].verified = true; | ||||
|                     } | ||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || | ||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, | ||||
|                                                     UserInfo_.userinfo.email)) { | ||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||
|                     } | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { | ||||
|                     std::string Secret; | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { | ||||
| @@ -302,10 +241,13 @@ namespace OpenWifi { | ||||
|                     } else { | ||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); | ||||
|                     } | ||||
|                 } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) { | ||||
|                     // nothing to do for email. | ||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 } | ||||
|                 Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method; | ||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; | ||||
|             } else { | ||||
|                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); | ||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); | ||||
| @@ -313,7 +255,6 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Existing.modified = OpenWifi::Now(); | ||||
|         if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||
|             SecurityObjects::UserInfo   NewUserInfo; | ||||
|             StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/user/{id}"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoDelete() final; | ||||
|   | ||||
| @@ -4,55 +4,51 @@ | ||||
|  | ||||
| #include "RESTAPI_users_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_protocol.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     void RESTAPI_users_handler::DoGet() { | ||||
|         std::vector<SecurityObjects::UserInfo> Users; | ||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); | ||||
|         auto nameSearch = GetParameter("nameSearch"); | ||||
|         auto emailSearch = GetParameter("emailSearch"); | ||||
|  | ||||
|         std::string baseQuery; | ||||
|         if(!nameSearch.empty() || !emailSearch.empty()) { | ||||
|             if(!nameSearch.empty()) | ||||
|                 baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) ); | ||||
|             if(!emailSearch.empty()) | ||||
|                 baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch)) | ||||
|                                                : fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch)); | ||||
|         } | ||||
|  | ||||
|         if(QB_.Select.empty()) { | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             if(StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, baseQuery)) { | ||||
|                 for (auto &i : Users.users) { | ||||
|                     Sanitize(UserInfo_, i); | ||||
|                 } | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             Poco::JSON::Object Answer; | ||||
|             if (StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||
|                 for (auto &i : Users) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                     Poco::JSON::Array   Arr; | ||||
|                     for(const auto &i:Users.users) | ||||
|                         Arr.add(i.id); | ||||
|                     Poco::JSON::Object  Answer; | ||||
|                     Answer.set("users", Arr); | ||||
|                     return ReturnObject(Answer); | ||||
|                         ArrayObj.add(i.id); | ||||
|                     } else { | ||||
|                         Sanitize(UserInfo_, i); | ||||
|                         i.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     } | ||||
|                 } | ||||
|             Poco::JSON::Object  Answer; | ||||
|             Users.to_json(Answer); | ||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             } | ||||
|             return ReturnObject(Answer); | ||||
|         } else { | ||||
|             SecurityObjects::UserInfoList   Users; | ||||
|             Poco::JSON::Array ArrayObj; | ||||
|             for(auto &i:SelectedRecords()) { | ||||
|                 SecurityObjects::UserInfo   UInfo; | ||||
|                 auto tI{i}; | ||||
|                 if(StorageService()->UserDB().GetUserById(i,UInfo)) { | ||||
|                     Poco::JSON::Object Obj; | ||||
|                     if (IdOnly) { | ||||
|                         ArrayObj.add(UInfo.id); | ||||
|                     } else { | ||||
|                         Sanitize(UserInfo_, UInfo); | ||||
|                     Users.users.emplace_back(UInfo); | ||||
|                 } | ||||
|             } | ||||
|             Poco::JSON::Object Answer; | ||||
|             Users.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|                         UInfo.to_json(Obj); | ||||
|                         ArrayObj.add(Obj); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Poco::JSON::Object RetObj; | ||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); | ||||
|             return ReturnObject(RetObj); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                                   Server, | ||||
|                                   TransactionId, | ||||
|                                   Internal) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/users"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                           Server, | ||||
|                           TransactionId, | ||||
|                           Internal) {}; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/validateSubToken"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateSubToken"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal) {}; | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/validateToken"}; }; | ||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateToken"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|   | ||||
| @@ -1,624 +0,0 @@ | ||||
| // | ||||
| // 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; | ||||
|     } | ||||
| } | ||||
| @@ -1,422 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2022-01-10. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "RESTAPI_ProvObjects.h" | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     namespace AnalyticsObjects { | ||||
|  | ||||
|         struct Report { | ||||
|             uint64_t snapShot = 0; | ||||
|  | ||||
|             void reset(); | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|         }; | ||||
|  | ||||
|         struct VenueInfo { | ||||
|             OpenWifi::Types::UUID_t id; | ||||
|             std::string name; | ||||
|             std::string description; | ||||
|             uint64_t retention = 0; | ||||
|             uint64_t interval = 0; | ||||
|             bool monitorSubVenues = false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct BoardInfo { | ||||
|             ProvObjects::ObjectInfo info; | ||||
|             std::vector<VenueInfo> venueList; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|             inline bool operator<(const BoardInfo &bb) const { | ||||
|                 return info.id < bb.info.id; | ||||
|             } | ||||
|  | ||||
|             inline bool operator==(const BoardInfo &bb) const { | ||||
|                 return info.id == bb.info.id; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         struct DeviceInfo { | ||||
|             std::string boardId; | ||||
|             std::string type; | ||||
|             std::string serialNumber; | ||||
|             std::string deviceType; | ||||
|             uint64_t lastContact = 0 ; | ||||
|             uint64_t lastPing = 0; | ||||
|             uint64_t lastState = 0; | ||||
|             std::string lastFirmware; | ||||
|             uint64_t lastFirmwareUpdate = 0; | ||||
|             uint64_t lastConnection = 0; | ||||
|             uint64_t lastDisconnection = 0; | ||||
|             uint64_t pings = 0; | ||||
|             uint64_t states = 0; | ||||
|             bool connected = false; | ||||
|             std::string connectionIp; | ||||
|             uint64_t associations_2g = 0; | ||||
|             uint64_t associations_5g = 0; | ||||
|             uint64_t associations_6g = 0; | ||||
|             uint64_t health = 0; | ||||
|             uint64_t lastHealth = 0; | ||||
|             std::string locale; | ||||
|             uint64_t uptime = 0; | ||||
|             double memory = 0.0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct DeviceInfoList { | ||||
|             std::vector<DeviceInfo> devices; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum wifi_band { | ||||
|             band_2g = 0, band_5g = 1, band_6g = 2 | ||||
|         }; | ||||
|  | ||||
|         struct TIDstat_entry { | ||||
|             uint64_t rx_msdu = 0, | ||||
|                     tx_msdu = 0, | ||||
|                     tx_msdu_failed = 0, | ||||
|                     tx_msdu_retries = 0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UE_rate { | ||||
|             uint64_t    bitrate=0; | ||||
|             uint64_t    mcs=0; | ||||
|             uint64_t    nss=0; | ||||
|             bool        ht=false; | ||||
|             bool        sgi=false; | ||||
|             uint64_t    chwidth=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct AveragePoint { | ||||
|             double      min = 0.0, | ||||
|                         max = 0.0, | ||||
|                         avg = 0.0; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UETimePoint { | ||||
|             std::string station; | ||||
|             int64_t rssi = 0; | ||||
|             uint64_t tx_bytes = 0, | ||||
|                     rx_bytes = 0, | ||||
|                     tx_duration = 0, | ||||
|                     rx_packets = 0, | ||||
|                     tx_packets = 0, | ||||
|                     tx_retries = 0, | ||||
|                     tx_failed = 0, | ||||
|                     connected = 0, | ||||
|                     inactive = 0; | ||||
|  | ||||
|             double  tx_bytes_bw = 0.0 , | ||||
|                     rx_bytes_bw = 0.0 , | ||||
|                     tx_packets_bw = 0.0 , | ||||
|                     rx_packets_bw = 0.0 , | ||||
|                     tx_failed_pct = 0.0 , | ||||
|                     tx_retries_pct = 0.0 , | ||||
|                     tx_duration_pct = 0.0; | ||||
|  | ||||
|             uint64_t    tx_bytes_delta = 0, | ||||
|                         rx_bytes_delta = 0, | ||||
|                         tx_duration_delta = 0, | ||||
|                         rx_packets_delta = 0, | ||||
|                         tx_packets_delta = 0, | ||||
|                         tx_retries_delta = 0, | ||||
|                         tx_failed_delta = 0; | ||||
|  | ||||
|             UE_rate tx_rate, | ||||
|                     rx_rate; | ||||
|             std::vector<TIDstat_entry> tidstats; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum SSID_MODES { | ||||
|             unknown = 0, | ||||
|             ap, | ||||
|             mesh, | ||||
|             sta, | ||||
|             wds_ap, | ||||
|             wds_sta, | ||||
|             wds_repeater | ||||
|         }; | ||||
|  | ||||
|         inline SSID_MODES SSID_Mode(const std::string &m) { | ||||
|             if (m == "ap") | ||||
|                 return ap; | ||||
|             if (m == "sta") | ||||
|                 return sta; | ||||
|             if (m == "mesh") | ||||
|                 return mesh; | ||||
|             if (m == "wds-ap") | ||||
|                 return wds_ap; | ||||
|             if (m == "wds-sta") | ||||
|                 return wds_sta; | ||||
|             if (m == "wds-repeater") | ||||
|                 return wds_repeater; | ||||
|             return unknown; | ||||
|         } | ||||
|  | ||||
|         struct SSIDTimePoint { | ||||
|             std::string bssid, | ||||
|                         mode, | ||||
|                         ssid; | ||||
|             uint64_t    band=0, | ||||
|                         channel=0; | ||||
|             std::vector<UETimePoint> associations; | ||||
|  | ||||
|             AveragePoint    tx_bytes_bw, | ||||
|                             rx_bytes_bw, | ||||
|                             tx_packets_bw, | ||||
|                             rx_packets_bw, | ||||
|                             tx_failed_pct, | ||||
|                             tx_retries_pct, | ||||
|                             tx_duration_pct; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|  | ||||
|         struct APTimePoint { | ||||
|             uint64_t    collisions = 0, | ||||
|                         multicast = 0, | ||||
|                         rx_bytes = 0, | ||||
|                         rx_dropped = 0, | ||||
|                         rx_errors = 0, | ||||
|                         rx_packets = 0, | ||||
|                         tx_bytes = 0, | ||||
|                         tx_dropped = 0, | ||||
|                         tx_errors = 0, | ||||
|                         tx_packets = 0; | ||||
|  | ||||
|             double      tx_bytes_bw = 0.0 , | ||||
|                         rx_bytes_bw = 0.0 , | ||||
|                         rx_dropped_pct = 0.0, | ||||
|                         tx_dropped_pct = 0.0, | ||||
|                         rx_packets_bw = 0.0, | ||||
|                         tx_packets_bw = 0.0, | ||||
|                         rx_errors_pct = 0.0 , | ||||
|                         tx_errors_pct = 0.0; | ||||
|  | ||||
|             uint64_t    tx_bytes_delta = 0, | ||||
|                         rx_bytes_delta = 0 , | ||||
|                         rx_dropped_delta = 0, | ||||
|                         tx_dropped_delta = 0, | ||||
|                         rx_packets_delta = 0, | ||||
|                         tx_packets_delta = 0, | ||||
|                         rx_errors_delta = 0, | ||||
|                         tx_errors_delta = 0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct RadioTimePoint { | ||||
|             uint64_t    band = 0, | ||||
|                         channel_width = 0; | ||||
|             uint64_t    active_ms = 0, | ||||
|                         busy_ms = 0, | ||||
|                         receive_ms = 0, | ||||
|                         transmit_ms = 0, | ||||
|                         tx_power = 0, | ||||
|                         channel = 0; | ||||
|             int64_t     temperature = 0, | ||||
|                         noise = 0; | ||||
|  | ||||
|             double      active_pct = 0.0 , | ||||
|                         busy_pct = 0.0, | ||||
|                         receive_pct = 0.0, | ||||
|                         transmit_pct = 0.0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|  | ||||
|         struct DeviceTimePoint { | ||||
|             std::string                     id; | ||||
|             std::string                     boardId; | ||||
|             uint64_t                        timestamp = 0; | ||||
|             APTimePoint                     ap_data; | ||||
|             std::vector<SSIDTimePoint>      ssid_data; | ||||
|             std::vector<RadioTimePoint>     radio_data; | ||||
|             AnalyticsObjects::DeviceInfo    device_info; | ||||
|             std::string                     serialNumber; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|             inline bool operator<(const DeviceTimePoint &rhs) const { | ||||
|                 if(timestamp < rhs.timestamp) | ||||
|                     return true; | ||||
|                 if(timestamp > rhs.timestamp) | ||||
|                     return false; | ||||
|                 if(device_info.serialNumber < rhs.device_info.serialNumber) | ||||
|                     return true; | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             inline bool operator==(const DeviceTimePoint &rhs) const { | ||||
|                 return timestamp==rhs.timestamp && device_info.serialNumber==rhs.device_info.serialNumber; | ||||
|             } | ||||
|  | ||||
|             inline bool operator>(const DeviceTimePoint &rhs) const { | ||||
|                 if(timestamp > rhs.timestamp) | ||||
|                     return true; | ||||
|                 if(timestamp < rhs.timestamp) | ||||
|                     return false; | ||||
|                 if(device_info.serialNumber > rhs.device_info.serialNumber) | ||||
|                     return true; | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointAnalysis { | ||||
|             uint64_t        timestamp; | ||||
|  | ||||
|             AveragePoint    noise; | ||||
|             AveragePoint    temperature; | ||||
|             AveragePoint    active_pct; | ||||
|             AveragePoint    busy_pct; | ||||
|             AveragePoint    receive_pct; | ||||
|             AveragePoint    transmit_pct; | ||||
|             AveragePoint    tx_power; | ||||
|  | ||||
|             AveragePoint    tx_bytes_bw; | ||||
|             AveragePoint    rx_bytes_bw; | ||||
|             AveragePoint    rx_dropped_pct; | ||||
|             AveragePoint    tx_dropped_pct; | ||||
|             AveragePoint    rx_packets_bw; | ||||
|             AveragePoint    tx_packets_bw; | ||||
|             AveragePoint    rx_errors_pct; | ||||
|             AveragePoint    tx_errors_pct; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointList { | ||||
|             std::vector<DeviceTimePoint>            points; | ||||
|             std::vector<DeviceTimePointAnalysis>    stats; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct BandwidthAnalysisEntry { | ||||
|             uint64_t    timestamp = 0; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct BandwidthAnalysis { | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         struct AverageValueSigned { | ||||
|             int64_t     peak=0, avg=0, low=0; | ||||
|         }; | ||||
|  | ||||
|         struct AverageValueUnsigned { | ||||
|             uint64_t     peak=0, avg=0, low=0; | ||||
|         }; | ||||
|  | ||||
|         struct RadioAnalysis { | ||||
|             uint64_t                timestamp=0; | ||||
|             AverageValueSigned      noise, temperature; | ||||
|             AverageValueUnsigned    active_ms, | ||||
|                                     busy_ms, | ||||
|                                     transmit_ms, | ||||
|                                     receive_ms; | ||||
|         }; | ||||
|  | ||||
|         struct DeviceTimePointStats { | ||||
|             uint64_t                firstPoint=0; | ||||
|             uint64_t                lastPoint=0; | ||||
|             uint64_t                count=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct WifiClientRate { | ||||
|             uint32_t    bitrate=0; | ||||
|             uint32_t    chwidth=0; | ||||
|             uint16_t    mcs=0; | ||||
|             uint16_t    nss=0; | ||||
|             bool        vht=false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct WifiClientHistory { | ||||
|             uint64_t        timestamp=OpenWifi::Now(); | ||||
|             std::string     station_id; | ||||
|             std::string     bssid; | ||||
|             std::string     ssid; | ||||
|             int64_t         rssi=0; | ||||
|             uint32_t        rx_bitrate=0; | ||||
|             uint32_t        rx_chwidth=0; | ||||
|             uint16_t        rx_mcs=0; | ||||
|             uint16_t        rx_nss=0; | ||||
|             bool            rx_vht=false; | ||||
|             uint32_t        tx_bitrate=0; | ||||
|             uint32_t        tx_chwidth=0; | ||||
|             uint16_t        tx_mcs=0; | ||||
|             uint16_t        tx_nss=0; | ||||
|             bool            tx_vht=false; | ||||
|             uint64_t        rx_bytes=0; | ||||
|             uint64_t        tx_bytes=0; | ||||
|             uint64_t        rx_duration=0; | ||||
|             uint64_t        tx_duration=0; | ||||
|             uint64_t        rx_packets=0; | ||||
|             uint64_t        tx_packets=0; | ||||
|             std::string     ipv4; | ||||
|             std::string     ipv6; | ||||
|             uint64_t        channel_width=0; | ||||
|             int64_t         noise=0; | ||||
|             uint64_t        tx_power=0; | ||||
|             uint64_t        channel=0; | ||||
|             uint64_t        active_ms=0; | ||||
|             uint64_t        busy_ms=0; | ||||
|             uint64_t        receive_ms=0; | ||||
|             std::string     mode; | ||||
|             int64_t         ack_signal=0; | ||||
|             int64_t         ack_signal_avg=0; | ||||
|             uint64_t        connected=0; | ||||
|             uint64_t        inactive=0; | ||||
|             uint64_t        tx_retries=0; | ||||
|             std::string     venue_id; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -3,12 +3,12 @@ | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_CertObjects.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
|  | ||||
| namespace OpenWifi::CertObjects { | ||||
| namespace OpenWifi { | ||||
|     namespace  CertObjects { | ||||
|         void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|             field_to_json(Obj,"id", id); | ||||
|             field_to_json(Obj,"entity", entity); | ||||
| @@ -29,7 +29,6 @@ namespace OpenWifi::CertObjects { | ||||
|             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) { | ||||
| @@ -53,7 +52,6 @@ namespace OpenWifi::CertObjects { | ||||
|                 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 (...) { | ||||
|             } | ||||
| @@ -176,33 +174,5 @@ namespace OpenWifi::CertObjects { | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|     void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "year", year); | ||||
|         field_to_json(Obj, "activeCerts", activeCerts); | ||||
|         field_to_json(Obj, "revokedCerts", revokedCerts); | ||||
|     } | ||||
|  | ||||
|     void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"snapshot", snapshot); | ||||
|         field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts); | ||||
|         field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts); | ||||
|         field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization); | ||||
|         field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization); | ||||
|         field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors); | ||||
|         field_to_json(Obj,"deviceTypes", deviceTypes); | ||||
|         field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts); | ||||
|         field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear); | ||||
|     } | ||||
|  | ||||
|     void Dashboard::reset() { | ||||
|         snapshot=0; | ||||
|         numberOfRevokedCerts = numberOfIssuedCerts = 0; | ||||
|         activeCertsPerOrganization.clear(); | ||||
|         revokedCertsPerOrganization.clear(); | ||||
|         numberOfRedirectors.clear(); | ||||
|         deviceTypes.clear(); | ||||
|         monthlyNumberOfCerts.clear(); | ||||
|         monthlyNumberOfCertsPerOrgPerYear.clear(); | ||||
|     } | ||||
| } | ||||
| @@ -5,10 +5,13 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| namespace OpenWifi::CertObjects { | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     namespace CertObjects { | ||||
|  | ||||
|         struct CertificateEntry { | ||||
|             OpenWifi::Types::UUID_t         id; | ||||
| @@ -30,7 +33,6 @@ namespace OpenWifi::CertObjects { | ||||
|             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); | ||||
| @@ -95,28 +97,5 @@ namespace OpenWifi::CertObjects { | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|     struct DashBoardYearlyStats { | ||||
|         uint64_t                            year=0; | ||||
|         OpenWifi::Types::Counted3DMapSII    activeCerts; | ||||
|         OpenWifi::Types::Counted3DMapSII    revokedCerts; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|     }; | ||||
|  | ||||
|     struct Dashboard { | ||||
|         uint64_t                            snapshot=0; | ||||
|         uint64_t                            numberOfIssuedCerts=0; | ||||
|         uint64_t                            numberOfRevokedCerts=0; | ||||
|         OpenWifi::Types::CountedMap         activeCertsPerOrganization; | ||||
|         OpenWifi::Types::CountedMap         revokedCertsPerOrganization; | ||||
|         OpenWifi::Types::CountedMap         numberOfRedirectors; | ||||
|         OpenWifi::Types::CountedMap         deviceTypes; | ||||
|         OpenWifi::Types::CountedMap         monthlyNumberOfCerts; | ||||
|         std::vector<DashBoardYearlyStats>   monthlyNumberOfCertsPerOrgPerYear; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         void reset(); | ||||
|     }; | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -233,10 +233,10 @@ namespace OpenWifi::FMSObjects { | ||||
|         UnknownFirmwares_.clear(); | ||||
|         totalSecondsOld_.clear(); | ||||
|         numberOfDevices = 0 ; | ||||
|         snapshot = OpenWifi::Now(); | ||||
|         snapshot = std::time(nullptr); | ||||
|     } | ||||
|  | ||||
|     bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool DeviceReport::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|  | ||||
|             return true; | ||||
| @@ -245,65 +245,4 @@ namespace OpenWifi::FMSObjects { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceInformation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "serialNumber",serialNumber); | ||||
|         field_to_json(Obj, "history", history); | ||||
|         field_to_json(Obj, "currentFirmware", currentFirmware); | ||||
|         field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmware", latestFirmware); | ||||
|         field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); | ||||
|         field_to_json(Obj, "latestFirmwareURI",latestFirmwareURI); | ||||
|     } | ||||
|  | ||||
|     bool DeviceInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "serialNumber",serialNumber); | ||||
|             field_from_json(Obj, "history", history); | ||||
|             field_from_json(Obj, "currentFirmware", currentFirmware); | ||||
|             field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmware", latestFirmware); | ||||
|             field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); | ||||
|             field_from_json(Obj, "latestFirmwareURI",latestFirmwareURI); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "serialNumber",serialNumber); | ||||
|         field_to_json(Obj, "revision", revision); | ||||
|         field_to_json(Obj, "upgraded", upgraded); | ||||
|     } | ||||
|  | ||||
|     bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "serialNumber",serialNumber); | ||||
|             field_from_json(Obj, "revision", revision); | ||||
|             field_from_json(Obj, "upgraded", upgraded); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "devices",devices); | ||||
|     } | ||||
|  | ||||
|     bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "devices",devices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,9 @@ | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #pragma once | ||||
| #ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
| #define UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
|  | ||||
|  | ||||
| #include "RESTAPI_SecurityObjects.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| @@ -27,7 +29,7 @@ namespace OpenWifi::FMSObjects { | ||||
|         std::string     location; | ||||
|         std::string     uploader; | ||||
|         std::string     digest; | ||||
|         bool            latest=false; | ||||
|         bool            latest=0; | ||||
|         SecurityObjects::NoteInfoVec    notes; | ||||
|         uint64_t        created=0; | ||||
|  | ||||
| @@ -125,35 +127,7 @@ namespace OpenWifi::FMSObjects { | ||||
|         void reset(); | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceInformation { | ||||
|         std::string                 serialNumber; | ||||
|         RevisionHistoryEntryList    history; | ||||
|         std::string                 currentFirmware; | ||||
|         uint64_t                    currentFirmwareDate=0; | ||||
|         std::string                 latestFirmware; | ||||
|         uint64_t                    latestFirmwareDate=0; | ||||
|         bool                        latestFirmwareAvailable; | ||||
|         std::string                 latestFirmwareURI; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceCurrentInfo { | ||||
|         std::string                 serialNumber; | ||||
|         std::string                 revision; | ||||
|         uint64_t                    upgraded=0; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct DeviceCurrentInfoList { | ||||
|         std::vector<DeviceCurrentInfo>  devices; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H | ||||
|   | ||||
| @@ -27,7 +27,7 @@ namespace OpenWifi::GWObjects { | ||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible)); | ||||
| #endif | ||||
| 		field_to_json(Obj,"macAddress", MACAddress); | ||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||
| @@ -45,10 +45,6 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"compatible", Compatible); | ||||
| 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | ||||
| 		field_to_json(Obj,"devicePassword", DevicePassword); | ||||
| 		field_to_json(Obj,"subscriber", subscriber); | ||||
| 		field_to_json(Obj,"entity", entity); | ||||
| 		field_to_json(Obj,"modified", modified); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
| 	} | ||||
|  | ||||
| 	void Device::to_json_with_status(Poco::JSON::Object &Obj) const { | ||||
| @@ -73,7 +69,7 @@ namespace OpenWifi::GWObjects { | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool Device::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||
| 			field_from_json(Obj,"deviceType",DeviceType); | ||||
| @@ -85,9 +81,6 @@ namespace OpenWifi::GWObjects { | ||||
| 			field_from_json(Obj,"location",Location); | ||||
| 			field_from_json(Obj,"venue",Venue); | ||||
| 			field_from_json(Obj,"compatible",Compatible); | ||||
| 			field_from_json(Obj,"subscriber", subscriber); | ||||
| 			field_from_json(Obj,"entity", entity); | ||||
| 			field_from_json(Obj,"locale", locale); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| @@ -156,7 +149,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"executionTime", executionTime); | ||||
| 	} | ||||
|  | ||||
| 	bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",Name); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| @@ -175,7 +168,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"created", created); | ||||
| 	} | ||||
|  | ||||
| 	bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"author",author); | ||||
| @@ -202,7 +195,6 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"websocketPackets", websocketPackets); | ||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); | ||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
|  | ||||
| 		switch(VerifiedCertificate) { | ||||
| 			case NO_CERTIFICATE: | ||||
| @@ -264,7 +256,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		lastContact.clear(); | ||||
| 		associations.clear(); | ||||
| 		numberOfDevices = 0 ; | ||||
| 		snapshot = OpenWifi::Now(); | ||||
| 		snapshot = std::time(nullptr); | ||||
| 	} | ||||
|  | ||||
| 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | ||||
| @@ -272,100 +264,5 @@ namespace OpenWifi::GWObjects { | ||||
| 		field_to_json(Obj,"capabilities", capabilities); | ||||
| 	}; | ||||
|  | ||||
| 	void ScriptRequest::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber",serialNumber); | ||||
| 		field_to_json(Obj,"timeout",timeout); | ||||
| 		field_to_json(Obj,"type",type); | ||||
| 		field_to_json(Obj,"script",script); | ||||
| 		field_to_json(Obj,"scriptId",scriptId); | ||||
| 		field_to_json(Obj,"when",when); | ||||
| 	} | ||||
|  | ||||
| 	bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"timeout",timeout); | ||||
| 			field_from_json(Obj,"type",type); | ||||
| 			field_from_json(Obj,"script",script); | ||||
| 			field_from_json(Obj,"scriptId",scriptId); | ||||
| 			field_from_json(Obj,"when",when); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"pools",pools); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"pools",pools); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"name",name); | ||||
| 		field_to_json(Obj,"description",description); | ||||
| 		field_to_json(Obj,"authConfig",authConfig); | ||||
| 		field_to_json(Obj,"acctConfig",acctConfig); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",name); | ||||
| 			field_from_json(Obj,"description",description); | ||||
| 			field_from_json(Obj,"authConfig",authConfig); | ||||
| 			field_from_json(Obj,"acctConfig",acctConfig); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"policy",strategy); | ||||
| 		field_to_json(Obj,"monitor",monitor); | ||||
| 		field_to_json(Obj,"monitorMethod",monitorMethod); | ||||
| 		field_to_json(Obj,"methodParameters",methodParameters); | ||||
| 		field_to_json(Obj,"servers",servers); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"policy",strategy); | ||||
| 			field_from_json(Obj,"monitor",monitor); | ||||
| 			field_from_json(Obj,"monitorMethod",monitorMethod); | ||||
| 			field_from_json(Obj,"methodParameters",methodParameters); | ||||
| 			field_from_json(Obj,"servers",servers); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"name",name); | ||||
| 		field_to_json(Obj,"ip",ip); | ||||
| 		field_to_json(Obj,"port",port); | ||||
| 		field_to_json(Obj,"weight",weight); | ||||
| 	} | ||||
|  | ||||
| 	bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",name); | ||||
| 			field_from_json(Obj,"ip",ip); | ||||
| 			field_from_json(Obj,"port",port); | ||||
| 			field_from_json(Obj,"weight",weight); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -37,7 +37,6 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t 	webSocketClients=0; | ||||
| 		uint64_t 	kafkaPackets=0; | ||||
| 		uint64_t 	websocketPackets=0; | ||||
| 		std::string locale; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| @@ -60,14 +59,9 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t LastFWUpdate = 0 ; | ||||
| 		std::string Venue; | ||||
| 		std::string DevicePassword; | ||||
| 		std::string subscriber; | ||||
| 		std::string entity; | ||||
| 		uint64_t 	modified=0; | ||||
| 		std::string locale; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 		void Print() const; | ||||
| 	}; | ||||
|  | ||||
| @@ -124,7 +118,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		uint64_t 	Created; | ||||
| 		uint64_t 	LastModified; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool 		from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool 		from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct CommandDetails { | ||||
| @@ -156,7 +150,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		std::string author; | ||||
| 		uint64_t created; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RttySessionDetails { | ||||
| @@ -199,53 +193,4 @@ namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct ScriptRequest { | ||||
| 		uint64_t 	timeout=30; | ||||
| 		std::string serialNumber; | ||||
| 		std::string type; | ||||
| 		std::string script; | ||||
| 		std::string scriptId; | ||||
| 		uint64_t 	when=0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyServerEntry { | ||||
| 		std::string name; | ||||
| 		std::string ip; | ||||
| 		uint16_t 	port=0; | ||||
| 		uint64_t 	weight=0; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyServerConfig { | ||||
| 		std::string 	strategy; | ||||
| 		bool 			monitor=false; | ||||
| 		std::string 	monitorMethod; | ||||
| 		std::vector<std::string>	methodParameters; | ||||
| 		std::vector<RadiusProxyServerEntry>	servers; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct 	RadiusProxyPool { | ||||
| 		std::string name; | ||||
| 		std::string description; | ||||
| 		RadiusProxyServerConfig	authConfig; | ||||
| 		RadiusProxyServerConfig	acctConfig; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RadiusProxyPoolList { | ||||
| 		std::vector<RadiusProxyPool>	pools; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -1,110 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2021-08-31. | ||||
| // | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
| using OpenWifi::RESTAPI_utils::EmbedDocument; | ||||
|  | ||||
| #include "RESTAPI_OWLSobjects.h" | ||||
|  | ||||
| // SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d | ||||
|  | ||||
| namespace OpenWifi::OWLSObjects { | ||||
|  | ||||
|     void SimulationDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"id", id); | ||||
|         field_to_json(Obj,"name", name); | ||||
|         field_to_json(Obj,"gateway", gateway); | ||||
|         field_to_json(Obj,"certificate", certificate); | ||||
|         field_to_json(Obj,"key", key); | ||||
|         field_to_json(Obj,"macPrefix", macPrefix); | ||||
|         field_to_json(Obj,"deviceType", deviceType); | ||||
|         field_to_json(Obj,"devices", devices); | ||||
|         field_to_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||
|         field_to_json(Obj,"stateInterval", stateInterval); | ||||
|         field_to_json(Obj,"minAssociations", minAssociations); | ||||
|         field_to_json(Obj,"maxAssociations", maxAssociations); | ||||
|         field_to_json(Obj,"minClients", minClients); | ||||
|         field_to_json(Obj,"maxClients", maxClients); | ||||
|         field_to_json(Obj,"simulationLength", simulationLength); | ||||
|         field_to_json(Obj,"threads", threads); | ||||
|         field_to_json(Obj,"clientInterval", clientInterval); | ||||
|         field_to_json(Obj,"keepAlive", keepAlive); | ||||
|         field_to_json(Obj,"reconnectInterval", reconnectInterval); | ||||
|         field_to_json(Obj,"concurrentDevices", concurrentDevices); | ||||
|     } | ||||
|  | ||||
|     bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"id", id); | ||||
|             field_from_json(Obj,"name", name); | ||||
|             field_from_json(Obj,"gateway", gateway); | ||||
|             field_from_json(Obj,"certificate", certificate); | ||||
|             field_from_json(Obj,"key", key); | ||||
|             field_from_json(Obj,"macPrefix", macPrefix); | ||||
|             field_from_json(Obj,"deviceType", deviceType); | ||||
|             field_from_json(Obj,"devices", devices); | ||||
|             field_from_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||
|             field_from_json(Obj,"stateInterval", stateInterval); | ||||
|             field_from_json(Obj,"minAssociations", minAssociations); | ||||
|             field_from_json(Obj,"maxAssociations", maxAssociations); | ||||
|             field_from_json(Obj,"minClients", minClients); | ||||
|             field_from_json(Obj,"maxClients", maxClients); | ||||
|             field_from_json(Obj,"simulationLength", simulationLength); | ||||
|             field_from_json(Obj,"threads", threads); | ||||
|             field_from_json(Obj,"clientInterval", clientInterval); | ||||
|             field_from_json(Obj,"keepAlive", keepAlive); | ||||
|             field_from_json(Obj,"reconnectInterval", reconnectInterval); | ||||
|             field_from_json(Obj,"concurrentDevices", concurrentDevices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"list", list); | ||||
|     } | ||||
|  | ||||
|     bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"list", list); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SimulationStatus::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"id", id); | ||||
|         field_to_json(Obj,"simulationId", simulationId); | ||||
|         field_to_json(Obj,"state", state); | ||||
|         field_to_json(Obj,"tx", tx); | ||||
|         field_to_json(Obj,"rx", rx); | ||||
|         field_to_json(Obj,"msgsTx", msgsTx); | ||||
|         field_to_json(Obj,"msgsRx", msgsRx); | ||||
|         field_to_json(Obj,"liveDevices", liveDevices); | ||||
|         field_to_json(Obj,"timeToFullDevices", timeToFullDevices); | ||||
|         field_to_json(Obj,"startTime", startTime); | ||||
|         field_to_json(Obj,"endTime", endTime); | ||||
|         field_to_json(Obj,"errorDevices", errorDevices); | ||||
|         field_to_json(Obj,"owner", owner); | ||||
|     } | ||||
|  | ||||
|     void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void Dashboard::reset() { | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,77 +0,0 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2021-08-31. | ||||
| // | ||||
|  | ||||
| #ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||
| #define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||
|  | ||||
| #include <vector> | ||||
| #include "Poco/JSON/Object.h" | ||||
|  | ||||
| namespace OpenWifi::OWLSObjects { | ||||
|  | ||||
|     struct SimulationDetails { | ||||
|         std::string     id; | ||||
|         std::string     name; | ||||
|         std::string     gateway; | ||||
|         std::string     certificate; | ||||
|         std::string     key; | ||||
|         std::string     macPrefix; | ||||
|         std::string     deviceType; | ||||
|         uint64_t        devices = 5; | ||||
|         uint64_t        healthCheckInterval = 60; | ||||
|         uint64_t        stateInterval = 60 ; | ||||
|         uint64_t        minAssociations = 1; | ||||
|         uint64_t        maxAssociations = 3; | ||||
|         uint64_t        minClients = 1 ; | ||||
|         uint64_t        maxClients = 3; | ||||
|         uint64_t        simulationLength = 60 * 60; | ||||
|         uint64_t        threads = 16; | ||||
|         uint64_t        clientInterval = 1; | ||||
|         uint64_t        keepAlive = 300; | ||||
|         uint64_t        reconnectInterval = 30 ; | ||||
|         uint64_t        concurrentDevices = 5; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SimulationDetailsList { | ||||
|         std::vector<SimulationDetails>  list; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SimulationStatus { | ||||
|         std::string     id; | ||||
|         std::string     simulationId; | ||||
|         std::string     state; | ||||
|         uint64_t        tx; | ||||
|         uint64_t        rx; | ||||
|         uint64_t        msgsTx; | ||||
|         uint64_t        msgsRx; | ||||
|         uint64_t        liveDevices; | ||||
|         uint64_t        timeToFullDevices; | ||||
|         uint64_t        startTime; | ||||
|         uint64_t        endTime; | ||||
|         uint64_t        errorDevices; | ||||
|         std::string     owner; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     struct Dashboard { | ||||
|         int O; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         void reset(); | ||||
|  | ||||
|     }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||
| @@ -91,13 +91,8 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"devices",devices); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         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) { | ||||
| @@ -111,13 +106,8 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"devices",devices); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"managementPolicies", managementPolicies); | ||||
|             field_from_json( Obj,"managementRoles", managementRoles); | ||||
|             field_from_json( Obj,"maps", maps); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -152,16 +142,10 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"design",design); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"contacts",contacts); | ||||
|         field_to_json( Obj,"contact",contact); | ||||
|         field_to_json( Obj,"location",location); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         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) { | ||||
| @@ -176,16 +160,10 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"design",design); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"contacts",contacts); | ||||
|             field_from_json( Obj,"contact",contact); | ||||
|             field_from_json( Obj,"location",location); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"managementPolicies", managementPolicies); | ||||
|             field_from_json( Obj,"managementRoles", managementRoles); | ||||
|             field_from_json( Obj,"maps", maps); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             field_from_json( Obj,"boards", boards); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
| @@ -193,89 +171,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Operator::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"managementRoles",managementRoles); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"defaultOperator",defaultOperator); | ||||
|         field_to_json( Obj,"sourceIP",sourceIP); | ||||
|         field_to_json( Obj,"registrationId",registrationId); | ||||
|     } | ||||
|  | ||||
|     bool Operator::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"managementRoles",managementRoles); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"defaultOperator",defaultOperator); | ||||
|             field_from_json( Obj,"sourceIP",sourceIP); | ||||
|             field_from_json( Obj,"registrationId",registrationId); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"operators",operators); | ||||
|     } | ||||
|  | ||||
|     bool OperatorList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"operators",operators); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void ServiceClass::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"cost",cost); | ||||
|         field_to_json( Obj,"currency",currency); | ||||
|         field_to_json( Obj,"period",period); | ||||
|         field_to_json( Obj,"billingCode",billingCode); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"defaultService",defaultService); | ||||
|     } | ||||
|  | ||||
|     bool ServiceClass::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"cost",cost); | ||||
|             field_from_json( Obj,"currency",currency); | ||||
|             field_from_json( Obj,"period",period); | ||||
|             field_from_json( Obj,"billingCode",billingCode); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"defaultService",defaultService); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void ServiceClassList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"serviceClasses",serviceClasses); | ||||
|     } | ||||
|  | ||||
|     bool ServiceClassList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"serviceClasses",serviceClasses); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"id",id); | ||||
|         field_to_json( Obj,"entity",loginId); | ||||
| @@ -298,7 +193,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"users",users); | ||||
|         field_to_json( Obj,"entity",entity); | ||||
|         field_to_json( Obj,"venue",venue); | ||||
|     } | ||||
|  | ||||
|     bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -307,7 +201,6 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"users",users); | ||||
|             field_from_json( Obj,"entity",entity); | ||||
|             field_from_json( Obj,"venue",venue); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
| @@ -356,92 +249,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorLocation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type",type); | ||||
|         field_to_json( Obj,"buildingName",buildingName); | ||||
|         field_to_json( Obj,"addressLines",addressLines); | ||||
|         field_to_json( Obj,"city",city); | ||||
|         field_to_json( Obj,"state",state); | ||||
|         field_to_json( Obj,"postal",postal); | ||||
|         field_to_json( Obj,"country",country); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"geoCode",geoCode); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool OperatorLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"buildingName",buildingName); | ||||
|             field_from_json( Obj,"addressLines",addressLines); | ||||
|             field_from_json( Obj,"city",city); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"postal",postal); | ||||
|             field_from_json( Obj,"country",country); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"geoCode",geoCode); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubLocation::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type",type); | ||||
|         field_to_json( Obj,"buildingName",buildingName); | ||||
|         field_to_json( Obj,"addressLines",addressLines); | ||||
|         field_to_json( Obj,"city",city); | ||||
|         field_to_json( Obj,"state",state); | ||||
|         field_to_json( Obj,"postal",postal); | ||||
|         field_to_json( Obj,"country",country); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"geoCode",geoCode); | ||||
|     } | ||||
|  | ||||
|     bool SubLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"buildingName",buildingName); | ||||
|             field_from_json( Obj,"addressLines",addressLines); | ||||
|             field_from_json( Obj,"city",city); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"postal",postal); | ||||
|             field_from_json( Obj,"country",country); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"geoCode",geoCode); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorLocationList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "locations", locations); | ||||
|     } | ||||
|  | ||||
|     bool OperatorLocationList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "locations", locations); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Contact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type", to_string(type)); | ||||
| @@ -488,100 +295,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorContact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"title",title); | ||||
|         field_to_json( Obj,"salutation",salutation); | ||||
|         field_to_json( Obj,"firstname",firstname); | ||||
|         field_to_json( Obj,"lastname",lastname); | ||||
|         field_to_json( Obj,"initials",initials); | ||||
|         field_to_json( Obj,"visual",visual); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"primaryEmail",primaryEmail); | ||||
|         field_to_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|         field_to_json( Obj,"accessPIN",accessPIN); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|         field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool OperatorContact::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"title",title); | ||||
|             field_from_json( Obj,"salutation",salutation); | ||||
|             field_from_json( Obj,"firstname",firstname); | ||||
|             field_from_json( Obj,"lastname",lastname); | ||||
|             field_from_json( Obj,"initials",initials); | ||||
|             field_from_json( Obj,"visual",visual); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"primaryEmail",primaryEmail); | ||||
|             field_from_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|             field_from_json( Obj,"accessPIN",accessPIN); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubContact::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"title",title); | ||||
|         field_to_json( Obj,"salutation",salutation); | ||||
|         field_to_json( Obj,"firstname",firstname); | ||||
|         field_to_json( Obj,"lastname",lastname); | ||||
|         field_to_json( Obj,"initials",initials); | ||||
|         field_to_json( Obj,"visual",visual); | ||||
|         field_to_json( Obj,"mobiles",mobiles); | ||||
|         field_to_json( Obj,"phones",phones); | ||||
|         field_to_json( Obj,"primaryEmail",primaryEmail); | ||||
|         field_to_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|         field_to_json( Obj,"accessPIN",accessPIN); | ||||
|     } | ||||
|  | ||||
|     bool SubContact::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"title",title); | ||||
|             field_from_json( Obj,"salutation",salutation); | ||||
|             field_from_json( Obj,"firstname",firstname); | ||||
|             field_from_json( Obj,"lastname",lastname); | ||||
|             field_from_json( Obj,"initials",initials); | ||||
|             field_from_json( Obj,"visual",visual); | ||||
|             field_from_json( Obj,"mobiles",mobiles); | ||||
|             field_from_json( Obj,"phones",phones); | ||||
|             field_from_json( Obj,"primaryEmail",primaryEmail); | ||||
|             field_from_json( Obj,"secondaryEmail",secondaryEmail); | ||||
|             field_from_json( Obj,"accessPIN",accessPIN); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void OperatorContactList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "contacts", contacts); | ||||
|     } | ||||
|  | ||||
|     bool OperatorContactList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "contacts", contacts); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void InventoryTag::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json(Obj, "serialNumber", serialNumber); | ||||
| @@ -594,12 +307,9 @@ namespace OpenWifi::ProvObjects { | ||||
|         field_to_json(Obj, "location", location); | ||||
|         field_to_json(Obj, "contact", contact); | ||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         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) { | ||||
| @@ -615,32 +325,9 @@ namespace OpenWifi::ProvObjects { | ||||
|             field_from_json( Obj,"location",location); | ||||
|             field_from_json( Obj,"contact",contact); | ||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"state",state); | ||||
|             field_from_json( Obj,"devClass",devClass); | ||||
|             field_from_json( Obj,"locale",locale); | ||||
|             field_from_json( Obj,"realMacAddress",realMacAddress); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void InventoryConfigApplyResult::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||
|         field_to_json( Obj, "warnings", warnings); | ||||
|         field_to_json( Obj, "errors", errors); | ||||
|         field_to_json( Obj, "errorCode", errorCode); | ||||
|     } | ||||
|  | ||||
|     bool InventoryConfigApplyResult::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj, "appliedConfiguration", appliedConfiguration); | ||||
|             field_from_json( Obj, "warnings", warnings); | ||||
|             field_from_json( Obj, "errors", errors); | ||||
|             field_from_json( Obj, "errorCode", errorCode); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -655,7 +342,7 @@ namespace OpenWifi::ProvObjects { | ||||
|     bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"taglist",taglist); | ||||
|             return true; | ||||
|             return false; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
| @@ -686,14 +373,12 @@ namespace OpenWifi::ProvObjects { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||
|         field_to_json( Obj,"deviceTypes",deviceTypes); | ||||
|         field_to_json( Obj,"subscriberOnly",subscriberOnly); | ||||
|         field_to_json( Obj,"entity", entity); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|         field_to_json( Obj,"subscriber", subscriber); | ||||
|         field_to_json( Obj,"configuration",configuration); | ||||
|         field_to_json( Obj,"inUse",inUse); | ||||
|         field_to_json( Obj,"variables",variables); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"rrm",rrm); | ||||
|         field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|         field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||
|     } | ||||
|  | ||||
|     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -701,14 +386,12 @@ namespace OpenWifi::ProvObjects { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||
|             field_from_json( Obj,"deviceTypes",deviceTypes); | ||||
|             field_from_json( Obj,"configuration",configuration); | ||||
|             field_from_json( Obj,"inUse",inUse); | ||||
|             field_from_json( Obj,"variables",variables); | ||||
|             field_from_json( Obj,"subscriberOnly",subscriberOnly); | ||||
|             field_from_json( Obj,"entity", entity); | ||||
|             field_from_json( Obj,"venue", venue); | ||||
|             field_from_json( Obj,"subscriber", subscriber); | ||||
|             field_from_json( Obj,"configuration",configuration); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"rrm",rrm); | ||||
|             field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|             field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -787,16 +470,46 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, ACLACCESS A) { | ||||
|         switch(A) { | ||||
|             case READ: Obj.set(FieldName,"read"); break; | ||||
|             case MODIFY: Obj.set(FieldName,"modify"); break; | ||||
|             case CREATE: Obj.set(FieldName,"create"); break; | ||||
|             case DELETE: Obj.set(FieldName,"delete"); break; | ||||
|             case NONE: | ||||
|                 default: | ||||
|                     Obj.set(FieldName,"none"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, ACLACCESS &A) { | ||||
|         if(Obj->has(FieldName)) { | ||||
|             auto V = Obj->getValue<std::string>(FieldName); | ||||
|             if(V=="read") | ||||
|                 A = READ; | ||||
|             else if(V=="modify") | ||||
|                 A = MODIFY; | ||||
|             else if(V=="create") | ||||
|                 A = CREATE; | ||||
|             else if(V=="delete") | ||||
|                 A = DELETE; | ||||
|             else if(V=="none") | ||||
|                 A = NONE; | ||||
|             else | ||||
|                 throw Poco::Exception("invalid JSON"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "users", users); | ||||
|         field_to_json(Obj, "roles", roles); | ||||
|         RESTAPI_utils::field_to_json(Obj, "users", users); | ||||
|         RESTAPI_utils::field_to_json(Obj, "roles", roles); | ||||
|         field_to_json(Obj, "access", access); | ||||
|     } | ||||
|  | ||||
|     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "users", users); | ||||
|             field_from_json(Obj, "roles", roles); | ||||
|             RESTAPI_utils::field_from_json(Obj, "users", users); | ||||
|             RESTAPI_utils::field_from_json(Obj, "roles", roles); | ||||
|             field_from_json(Obj, "access", access); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
| @@ -806,12 +519,12 @@ namespace OpenWifi::ProvObjects { | ||||
|     } | ||||
|      | ||||
|     void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "list", list); | ||||
|         RESTAPI_utils::field_to_json(Obj, "list", list); | ||||
|     } | ||||
|  | ||||
|     bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "list", list); | ||||
|             RESTAPI_utils::field_from_json(Obj, "list", list); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -819,15 +532,44 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     std::string to_string(VISIBILITY A) { | ||||
|         switch(A) { | ||||
|             case PUBLIC: return "public"; | ||||
|             case SELECT: return "select"; | ||||
|             case PRIVATE: | ||||
|             default: | ||||
|                 return "private"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, VISIBILITY A) { | ||||
|         Obj.set(FieldName,to_string(A)); | ||||
|     } | ||||
|  | ||||
|     VISIBILITY visibility_from_string(const std::string &V) { | ||||
|         if(V=="public") | ||||
|             return PUBLIC; | ||||
|         else if(V=="select") | ||||
|             return SELECT; | ||||
|         else if(V=="private") | ||||
|             return PRIVATE; | ||||
|         throw Poco::Exception("invalid json"); | ||||
|     } | ||||
|  | ||||
|     void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, VISIBILITY &A) { | ||||
|         if(Obj->has(FieldName)) { | ||||
|             auto V = Obj->getValue<std::string>(FieldName); | ||||
|             A = visibility_from_string(V); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void Map::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"data",data); | ||||
|         field_to_json( Obj,"entity",entity); | ||||
|         field_to_json( Obj,"creator",creator); | ||||
|         RESTAPI_utils::field_to_json( Obj,"data",data); | ||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); | ||||
|         RESTAPI_utils::field_to_json( Obj,"creator",creator); | ||||
|         field_to_json( Obj,"visibility",visibility); | ||||
|         field_to_json( Obj,"access",access); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|         RESTAPI_utils::field_to_json( Obj,"access",access); | ||||
|     } | ||||
|  | ||||
|     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -836,24 +578,8 @@ namespace OpenWifi::ProvObjects { | ||||
|             RESTAPI_utils::field_from_json( Obj,"data",data); | ||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); | ||||
|             RESTAPI_utils::field_from_json( Obj,"creator",creator); | ||||
|             RESTAPI_utils::field_from_json( Obj,"visibility",visibility); | ||||
|             field_from_json( Obj,"visibility",visibility); | ||||
|             RESTAPI_utils::field_from_json( Obj,"access",access); | ||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             RESTAPI_utils::field_from_json( Obj,"venue", venue); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SerialNumberList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         RESTAPI_utils::field_to_json( Obj,"serialNumbers",serialNumbers); | ||||
|     } | ||||
|  | ||||
|     bool SerialNumberList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             RESTAPI_utils::field_from_json( Obj,"serialNumbers",serialNumbers); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
| @@ -875,223 +601,8 @@ namespace OpenWifi::ProvObjects { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SignupEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"email", email); | ||||
|         field_to_json( Obj,"userId", userId); | ||||
|         field_to_json( Obj,"macAddress", macAddress); | ||||
|         field_to_json( Obj,"serialNumber", serialNumber); | ||||
|         field_to_json( Obj,"submitted", submitted); | ||||
|         field_to_json( Obj,"completed", completed); | ||||
|         field_to_json( Obj,"status", status); | ||||
|         field_to_json( Obj,"error", error); | ||||
|         field_to_json( Obj,"statusCode", statusCode); | ||||
|         field_to_json( Obj,"deviceID", deviceID); | ||||
|         field_to_json( Obj,"registrationId",registrationId); | ||||
|         field_to_json( Obj,"operatorId",operatorId); | ||||
|     } | ||||
|  | ||||
|     bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"email", email); | ||||
|             field_from_json( Obj,"userId", userId); | ||||
|             field_from_json( Obj,"macAddress", macAddress); | ||||
|             field_from_json( Obj,"serialNumber", serialNumber); | ||||
|             field_from_json( Obj,"submitted", submitted); | ||||
|             field_from_json( Obj,"completed", completed); | ||||
|             field_from_json( Obj,"status", status); | ||||
|             field_from_json( Obj,"error", error); | ||||
|             field_from_json( Obj,"statusCode", statusCode); | ||||
|             field_from_json( Obj,"deviceID", deviceID); | ||||
|             field_from_json( Obj,"registrationId",registrationId); | ||||
|             field_from_json( Obj,"operatorId",operatorId); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Variable::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"type", type); | ||||
|         field_to_json( Obj,"weight", weight); | ||||
|         field_to_json( Obj,"prefix", prefix); | ||||
|         field_to_json( Obj,"value", value); | ||||
|     } | ||||
|  | ||||
|     bool Variable::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"type", type); | ||||
|             field_from_json( Obj,"weight", weight); | ||||
|             field_from_json( Obj,"prefix", prefix); | ||||
|             field_from_json( Obj,"value", value); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|     } | ||||
|  | ||||
|     bool VariableList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableBlock::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"variables", variables); | ||||
|         field_to_json( Obj,"entity", entity); | ||||
|         field_to_json( Obj,"venue", venue); | ||||
|         field_to_json( Obj,"subscriber", subscriber); | ||||
|         field_to_json( Obj,"inventory", inventory); | ||||
|         field_to_json( Obj,"configurations", configurations); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|     } | ||||
|  | ||||
|     bool VariableBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"variables", variables); | ||||
|             field_from_json( Obj,"entity", entity); | ||||
|             field_from_json( Obj,"venue", venue); | ||||
|             field_from_json( Obj,"subscriber", subscriber); | ||||
|             field_from_json( Obj,"inventory", inventory); | ||||
|             field_from_json( Obj,"configurations", configurations); | ||||
|             field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VariableBlockList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"variableBlocks", variableBlocks); | ||||
|     } | ||||
|  | ||||
|     bool VariableBlockList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"variableBlocks", variableBlocks); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"configuration", configuration); | ||||
|         field_to_json( Obj,"rrm", rrm); | ||||
|         field_to_json( Obj,"firmwareRCOnly", firmwareRCOnly); | ||||
|         field_to_json( Obj,"firmwareUpgrade", firmwareUpgrade); | ||||
|     } | ||||
|  | ||||
|     bool ConfigurationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"configuration", configuration); | ||||
|             field_from_json( Obj,"rrm", rrm); | ||||
|             field_from_json( Obj,"firmwareRCOnly", firmwareRCOnly); | ||||
|             field_from_json( Obj,"firmwareUpgrade", firmwareUpgrade); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { | ||||
|         info.to_json(Obj); | ||||
|         field_to_json( Obj,"serialNumber", serialNumber); | ||||
|         field_to_json( Obj,"deviceType", deviceType); | ||||
|         field_to_json( Obj,"operatorId", operatorId); | ||||
|         field_to_json( Obj,"subscriberId", subscriberId); | ||||
|         field_to_json( Obj,"location", location); | ||||
|         field_to_json( Obj,"contact", contact); | ||||
|         field_to_json( Obj,"managementPolicy", managementPolicy); | ||||
|         field_to_json( Obj,"serviceClass", serviceClass); | ||||
|         field_to_json( Obj,"qrCode", qrCode); | ||||
|         field_to_json( Obj,"geoCode", geoCode); | ||||
|         field_to_json( Obj,"deviceRules",deviceRules); | ||||
|         field_to_json( Obj,"state", state); | ||||
|         field_to_json( Obj,"locale", locale); | ||||
|         field_to_json( Obj,"billingCode", billingCode); | ||||
|         field_to_json( Obj,"configuration", configuration); | ||||
|         field_to_json( Obj,"suspended", suspended); | ||||
|         field_to_json( Obj,"realMacAddress", realMacAddress); | ||||
|     } | ||||
|  | ||||
|     bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             info.from_json(Obj); | ||||
|             field_from_json( Obj,"serialNumber", serialNumber); | ||||
|             field_from_json( Obj,"deviceType", deviceType); | ||||
|             field_from_json( Obj,"operatorId", operatorId); | ||||
|             field_from_json( Obj,"subscriberId", subscriberId); | ||||
|             field_from_json( Obj,"location", location); | ||||
|             field_from_json( Obj,"contact", contact); | ||||
|             field_from_json( Obj,"managementPolicy", managementPolicy); | ||||
|             field_from_json( Obj,"serviceClass", serviceClass); | ||||
|             field_from_json( Obj,"qrCode", qrCode); | ||||
|             field_from_json( Obj,"geoCode", geoCode); | ||||
|             field_from_json( Obj,"deviceRules",deviceRules); | ||||
|             field_from_json( Obj,"state", state); | ||||
|             field_from_json( Obj,"locale", locale); | ||||
|             field_from_json( Obj,"billingCode", billingCode); | ||||
|             field_from_json( Obj,"configuration", configuration); | ||||
|             field_from_json( Obj,"suspended", suspended); | ||||
|             field_from_json( Obj,"realMacAddress", realMacAddress); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json( Obj,"subscriberDevices", subscriberDevices); | ||||
|     } | ||||
|  | ||||
|     bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json( Obj,"subscriberDevices", subscriberDevices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void VenueDeviceList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"id",id); | ||||
|         field_to_json(Obj,"name",name); | ||||
|         field_to_json(Obj,"description",description); | ||||
|         field_to_json(Obj,"devices",devices); | ||||
|     } | ||||
|  | ||||
|     bool VenueDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"id",id); | ||||
|             field_from_json(Obj,"name",name); | ||||
|             field_from_json(Obj,"description",description); | ||||
|             field_from_json(Obj,"devices",devices); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         if(O->has("name")) | ||||
|             I.name = O->get("name").toString(); | ||||
|  | ||||
| @@ -1112,7 +623,7 @@ namespace OpenWifi::ProvObjects { | ||||
|     } | ||||
|  | ||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         uint64_t Now = OpenWifi::Now(); | ||||
|         uint64_t Now = std::time(nullptr); | ||||
|         if(O->has("name")) | ||||
|             I.name = O->get("name").toString(); | ||||
|  | ||||
| @@ -1134,30 +645,5 @@ namespace OpenWifi::ProvObjects { | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||
|         I.modified = I.created = OpenWifi::Now(); | ||||
|         I.id = MicroService::CreateUUID(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void DeviceRules::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"rcOnly",rcOnly); | ||||
|         field_to_json(Obj,"rrm",rrm); | ||||
|         field_to_json(Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|     } | ||||
|  | ||||
|     bool DeviceRules::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"rcOnly",rcOnly); | ||||
|             field_from_json(Obj,"rrm",rrm); | ||||
|             field_from_json(Obj,"firmwareUpgrade",firmwareUpgrade); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -33,13 +33,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SerialNumberList { | ||||
|         Types::UUIDvec_t    serialNumbers; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ManagementPolicyEntry { | ||||
|         Types::UUIDvec_t users; | ||||
|         Types::UUIDvec_t resources; | ||||
| @@ -55,22 +48,12 @@ namespace OpenWifi::ProvObjects { | ||||
|         std::vector<ManagementPolicyEntry>  entries; | ||||
|         Types::StringVec    inUse; | ||||
|         Types::UUID_t       entity; | ||||
|         Types::UUID_t       venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<ManagementPolicy>      ManagementPolicyVec; | ||||
|  | ||||
|     struct DeviceRules { | ||||
|         std::string     rcOnly{"inherit"}; | ||||
|         std::string     rrm{"inherit"}; | ||||
|         std::string     firmwareUpgrade{"inherit"}; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Entity { | ||||
|         ObjectInfo              info; | ||||
|         Types::UUID_t           parent; | ||||
| @@ -81,13 +64,8 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::UUID_t           managementPolicy; | ||||
|         Types::UUIDvec_t        deviceConfiguration; | ||||
|         Types::UUIDvec_t        devices; | ||||
|         DeviceRules             deviceRules; | ||||
|         std::string             rrm; | ||||
|         Types::StringVec        sourceIP; | ||||
|         Types::UUIDvec_t        variables; | ||||
|         Types::UUIDvec_t        managementPolicies; | ||||
|         Types::UUIDvec_t        managementRoles; | ||||
|         Types::UUIDvec_t        maps; | ||||
|         Types::UUIDvec_t        configurations; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -114,16 +92,10 @@ namespace OpenWifi::ProvObjects { | ||||
|         DiGraph             topology; | ||||
|         std::string         design; | ||||
|         Types::UUIDvec_t    deviceConfiguration; | ||||
|         Types::UUIDvec_t    contacts; | ||||
|         std::string         contact; | ||||
|         std::string         location; | ||||
|         DeviceRules         deviceRules; | ||||
|         std::string         rrm; | ||||
|         Types::StringVec    sourceIP; | ||||
|         Types::UUIDvec_t    variables; | ||||
|         Types::UUIDvec_t    configurations; | ||||
|         Types::UUIDvec_t    maps; | ||||
|         Types::UUIDvec_t    managementPolicies; | ||||
|         Types::UUIDvec_t    managementRoles; | ||||
|         Types::UUIDvec_t    boards; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -145,7 +117,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::UUIDvec_t    users; | ||||
|         Types::StringVec    inUse; | ||||
|         Types::UUID_t       entity; | ||||
|         Types::UUID_t       venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -209,51 +180,6 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|     typedef std::vector<Location>      LocationVec; | ||||
|  | ||||
|     struct OperatorLocation { | ||||
|         ObjectInfo          info; | ||||
|         std::string         type; | ||||
|         std::string         buildingName; | ||||
|         Types::StringVec    addressLines; | ||||
|         std::string         city; | ||||
|         std::string         state; | ||||
|         std::string         postal; | ||||
|         std::string         country; | ||||
|         Types::StringVec    phones; | ||||
|         Types::StringVec    mobiles; | ||||
|         std::string         geoCode; | ||||
|         Types::UUID_t       operatorId; | ||||
|         Types::UUID_t       subscriberDeviceId; | ||||
|         Types::UUID_t       managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<Location>      LocationVec; | ||||
|  | ||||
|     struct SubLocation { | ||||
|         std::string         type; | ||||
|         std::string         buildingName; | ||||
|         Types::StringVec    addressLines; | ||||
|         std::string         city; | ||||
|         std::string         state; | ||||
|         std::string         postal; | ||||
|         std::string         country; | ||||
|         Types::StringVec    phones; | ||||
|         Types::StringVec    mobiles; | ||||
|         std::string         geoCode; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorLocationList { | ||||
|         std::vector<OperatorLocation>    locations; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     enum ContactType { | ||||
|         CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER, | ||||
|         CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN | ||||
| @@ -317,55 +243,6 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|     typedef std::vector<Contact>      ContactVec; | ||||
|  | ||||
|     struct OperatorContact { | ||||
|         ObjectInfo      info; | ||||
|         std::string     type; | ||||
|         std::string     title; | ||||
|         std::string     salutation; | ||||
|         std::string     firstname; | ||||
|         std::string     lastname; | ||||
|         std::string     initials; | ||||
|         std::string     visual; | ||||
|         Types::StringVec mobiles; | ||||
|         Types::StringVec phones; | ||||
|         std::string     primaryEmail; | ||||
|         std::string     secondaryEmail; | ||||
|         std::string     accessPIN; | ||||
|         Types::UUID_t   operatorId; | ||||
|         Types::UUID_t   subscriberDeviceId; | ||||
|         Types::UUID_t   managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubContact { | ||||
|         std::string     type; | ||||
|         std::string     title; | ||||
|         std::string     salutation; | ||||
|         std::string     firstname; | ||||
|         std::string     lastname; | ||||
|         std::string     initials; | ||||
|         std::string     visual; | ||||
|         Types::StringVec mobiles; | ||||
|         Types::StringVec phones; | ||||
|         std::string     primaryEmail; | ||||
|         std::string     secondaryEmail; | ||||
|         std::string     accessPIN; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorContactList { | ||||
|         std::vector<OperatorContact>    contacts; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     typedef std::vector<OperatorContact>      OperatorContactVec; | ||||
|  | ||||
|     struct DeviceConfigurationElement { | ||||
|         std::string name; | ||||
|         std::string description; | ||||
| @@ -383,19 +260,16 @@ namespace OpenWifi::ProvObjects { | ||||
|         Types::StringVec                deviceTypes; | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         Types::StringVec                inUse; | ||||
|         Types::UUIDvec_t                variables; | ||||
|         DeviceRules                     deviceRules; | ||||
|         bool                            subscriberOnly=false; | ||||
|         std::string                     venue; | ||||
|         std::string                     entity; | ||||
|         std::string                     subscriber; | ||||
|         Types::StringPairVec            variables; | ||||
|         std::string                     rrm; | ||||
|         std::string                     firmwareUpgrade; | ||||
|         bool                            firmwareRCOnly=false; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|     typedef std::vector<DeviceConfiguration>      DeviceConfigurationVec; | ||||
|  | ||||
|  | ||||
|     struct InventoryTag { | ||||
|         ObjectInfo      info; | ||||
|         std::string     serialNumber; | ||||
| @@ -408,12 +282,9 @@ namespace OpenWifi::ProvObjects { | ||||
|         std::string     location; | ||||
|         std::string     contact; | ||||
|         std::string     deviceConfiguration; | ||||
|         DeviceRules     deviceRules; | ||||
|         std::string     rrm; | ||||
|         Types::UUID_t   managementPolicy; | ||||
|         std::string     state; | ||||
|         std::string     devClass; | ||||
|         std::string     locale; | ||||
|         std::string     realMacAddress; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -428,15 +299,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct InventoryConfigApplyResult { | ||||
|         std::string         appliedConfiguration; | ||||
|         Types::StringVec    errors; | ||||
|         Types::StringVec    warnings; | ||||
|         uint64_t            errorCode; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Report { | ||||
|         uint64_t            snapShot=0; | ||||
| @@ -471,20 +333,20 @@ namespace OpenWifi::ProvObjects { | ||||
|     }; | ||||
|  | ||||
|     struct UuidList { | ||||
|         Types::UUIDvec_t    list; | ||||
|         std::vector<std::string>    list; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum ACLACCESS { | ||||
|         NONE = 0, READ=1, MODIFY=2, CREATE=3, DELETE=4 | ||||
|         NONE, READ, MODIFY, CREATE, DELETE | ||||
|     }; | ||||
|  | ||||
|     struct ObjectACL { | ||||
|         UuidList        users; | ||||
|         UuidList        roles; | ||||
|         uint64_t        access = (uint64_t) NONE; | ||||
|         ACLACCESS       access = NONE; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -497,15 +359,20 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum VISIBILITY { | ||||
|         PUBLIC, PRIVATE, SELECT | ||||
|     }; | ||||
|  | ||||
|     std::string to_string(VISIBILITY A); | ||||
|     VISIBILITY visibility_from_string(const std::string &V); | ||||
|  | ||||
|     struct Map { | ||||
|         ObjectInfo          info; | ||||
|         std::string         data; | ||||
|         std::string         entity; | ||||
|         std::string         creator; | ||||
|         std::string         visibility{"private"}; | ||||
|         VISIBILITY          visibility = PRIVATE; | ||||
|         ObjectACLList       access; | ||||
|         Types::UUID_t       managementPolicy; | ||||
|         std::string         venue; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -518,168 +385,6 @@ namespace OpenWifi::ProvObjects { | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     enum SignupStatusCodes { | ||||
|         SignupCreated = 0 , | ||||
|         SignupWaitingForEmail, | ||||
|         SignupWaitingForDevice, | ||||
|         SignupSuccess, | ||||
|         SignupFailure, | ||||
|         SignupCanceled, | ||||
|         SignupTimedOut | ||||
|     }; | ||||
|  | ||||
|     struct SignupEntry { | ||||
|         ObjectInfo          info; | ||||
|         std::string         email; | ||||
|         std::string         userId; | ||||
|         std::string         macAddress; | ||||
|         std::string         serialNumber; | ||||
|         uint64_t            submitted = 0 ; | ||||
|         uint64_t            completed = 0 ; | ||||
|         std::string         status; | ||||
|         uint64_t            error=0; | ||||
|         uint64_t            statusCode=0; | ||||
|         std::string         deviceID; | ||||
|         std::string         registrationId; | ||||
|         std::string         operatorId; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Variable { | ||||
|         std::string         type; | ||||
|         uint64_t            weight=0; | ||||
|         std::string         prefix; | ||||
|         std::string         value; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableList { | ||||
|         std::vector<Variable>   variables; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableBlock { | ||||
|         ObjectInfo                  info; | ||||
|         std::vector<Variable>       variables; | ||||
|         std::string                 entity; | ||||
|         std::string                 venue; | ||||
|         std::string                 subscriber; | ||||
|         std::string                 inventory; | ||||
|         Types::UUIDvec_t            configurations; | ||||
|         Types::UUID_t               managementPolicy; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VariableBlockList { | ||||
|         std::vector<VariableBlock>      variableBlocks; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct Operator { | ||||
|         ObjectInfo                      info; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         Types::UUIDvec_t                managementRoles; | ||||
|         DeviceRules                     deviceRules; | ||||
|         std::vector<Variable>           variables; | ||||
|         bool                            defaultOperator=false; | ||||
|         Types::StringVec                sourceIP; | ||||
|         std::string                     registrationId; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct OperatorList { | ||||
|         std::vector<Operator>            operators; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct VenueDeviceList { | ||||
|         std::string         id; | ||||
|         std::string         name; | ||||
|         std::string         description; | ||||
|         Types::UUIDvec_t    devices; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ServiceClass { | ||||
|         ObjectInfo                      info; | ||||
|         Types::UUID_t                   operatorId; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         double                          cost=0.0; | ||||
|         std::string                     currency; | ||||
|         std::string                     period; | ||||
|         std::string                     billingCode; | ||||
|         std::vector<Variable>           variables; | ||||
|         bool                            defaultService=false; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ServiceClassList { | ||||
|         std::vector<ServiceClass>            serviceClasses; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct ConfigurationDetails { | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         std::string                     rrm{"inherit"}; | ||||
|         std::string                     firmwareUpgrade{"inherit"}; | ||||
|         std::string                     firmwareRCOnly{"inherit"}; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubscriberDevice { | ||||
|         ObjectInfo                      info; | ||||
|         std::string                     serialNumber; | ||||
|         std::string                     deviceType; | ||||
|         Types::UUID_t                   operatorId; | ||||
|         Types::UUID_t                   subscriberId; | ||||
|         SubLocation                     location; | ||||
|         SubContact                      contact; | ||||
|         Types::UUID_t                   managementPolicy; | ||||
|         Types::UUID_t                   serviceClass; | ||||
|         std::string                     qrCode; | ||||
|         std::string                     geoCode; | ||||
|         DeviceRules                     deviceRules; | ||||
|         std::string                     state; | ||||
|         std::string                     locale; | ||||
|         std::string                     billingCode; | ||||
|         DeviceConfigurationElementVec   configuration; | ||||
|         bool                            suspended=false; | ||||
|         std::string                     realMacAddress; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct SubscriberDeviceList { | ||||
|         std::vector<SubscriberDevice>       subscriberDevices; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||
|     bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||
| }; | ||||
|   | ||||
| @@ -95,7 +95,6 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "PortalLogin", PortalLogin_); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: AclTemplate" << std::endl; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -113,8 +112,6 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"userMustChangePassword",userMustChangePassword); | ||||
|         field_to_json(Obj,"errorCode", errorCode); | ||||
| 		Obj.set("aclTemplate",AclTemplateObj); | ||||
|         field_to_json(Obj,"errorCode", errorCode); | ||||
|         field_to_json(Obj,"lastRefresh", lastRefresh_); | ||||
| 	} | ||||
|  | ||||
| 	bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -131,10 +128,9 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "created", created_); | ||||
| 			field_from_json(Obj, "username", username_); | ||||
|             field_from_json(Obj, "userMustChangePassword",userMustChangePassword); | ||||
|             field_from_json(Obj,"lastRefresh", lastRefresh_); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|             std::cout << "Cannot parse: WebToken" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -145,14 +141,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"primary", primary); | ||||
| 	} | ||||
|  | ||||
| 	bool MobilePhoneNumber::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"number",number); | ||||
| 	        field_from_json(Obj,"verified",verified); | ||||
| 	        field_from_json(Obj,"primary",primary); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|             std::cout << "Cannot parse: MobilePhoneNumber" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	}; | ||||
| @@ -162,13 +158,13 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"method", method); | ||||
| 	} | ||||
|  | ||||
| 	bool MfaAuthInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"enabled",enabled); | ||||
| 	        field_from_json(Obj,"method",method); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|             std::cout << "Cannot parse: MfaAuthInfo" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -179,14 +175,14 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj, "authenticatorSecret", authenticatorSecret); | ||||
| 	} | ||||
|  | ||||
| 	bool UserLoginLoginExtensions::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj, "mobiles",mobiles); | ||||
| 	        field_from_json(Obj, "mfa",mfa); | ||||
|             field_from_json(Obj, "authenticatorSecret", authenticatorSecret); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|             std::cout << "Cannot parse: UserLoginLoginExtensions" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -198,7 +194,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj, "method", method); | ||||
|     } | ||||
|  | ||||
|     bool MFAChallengeRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"uuid",uuid); | ||||
| 	        field_from_json(Obj,"question",question); | ||||
| @@ -206,7 +202,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	        field_from_json(Obj,"method",method); | ||||
| 	        return true; | ||||
| 	    } catch (...) { | ||||
|             std::cout << "Cannot parse: MFAChallengeRequest" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	}; | ||||
| @@ -214,15 +210,16 @@ namespace OpenWifi::SecurityObjects { | ||||
|     void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "uuid", uuid); | ||||
|         field_to_json(Obj, "answer", answer); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     bool MFAChallengeResponse::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"uuid",uuid); | ||||
|             field_from_json(Obj,"answer",answer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|             std::cout << "Cannot parse: MFAChallengeResponse" << std::endl; | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|  | ||||
| @@ -260,7 +257,6 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"oauthType",oauthType); | ||||
| 		field_to_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||
|         field_to_json(Obj,"modified",modified); | ||||
|         field_to_json(Obj,"signingUp",signingUp); | ||||
|     }; | ||||
|  | ||||
|     bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -296,28 +292,13 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"oauthType",oauthType); | ||||
| 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||
|             field_from_json(Obj,"modified",modified); | ||||
|             field_from_json(Obj,"signingUp",signingUp); | ||||
|             return true; | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             std::cout << "Cannot parse: UserInfo" << std::endl; | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     }; | ||||
|  | ||||
|     void UserInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj,"users",users); | ||||
|     } | ||||
|  | ||||
|     bool UserInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"users",users); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|             std::cout << "Cannot parse: InternalServiceInfo" << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| 	void InternalServiceInfo::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"privateURI",privateURI); | ||||
| 		field_to_json(Obj,"publicURI",publicURI); | ||||
| @@ -331,7 +312,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"token",token); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|             std::cout << "Cannot parse: InternalServiceInfo" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -349,7 +330,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "services", services); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: InternalSystemServices" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -371,7 +352,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "authenticationType", authenticationType); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|             std::cout << "Cannot parse: SystemEndpoint" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	}; | ||||
| @@ -385,7 +366,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "endpoints", endpoints); | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
|             std::cout << "Cannot parse: SystemEndpointList" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -404,7 +385,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj, "userInfo", userinfo); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: UserInfoAndPolicy" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -415,14 +396,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"note", note); | ||||
| 	} | ||||
|  | ||||
| 	bool NoteInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"created",created); | ||||
| 			field_from_json(Obj,"createdBy",createdBy); | ||||
| 			field_from_json(Obj,"note",note); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: NoteInfo" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -433,20 +414,20 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	            SecurityObjects::NoteInfoVec NIV; | ||||
| 	            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString()); | ||||
| 	            for(auto const &i:NIV) { | ||||
| 	                SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	                SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	                Notes.push_back(ii); | ||||
| 	            } | ||||
| 	        } | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|             std::cout << "Cannot parse: MergeNotes" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
|  | ||||
| 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { | ||||
| 	    for(auto const &i:NewNotes) { | ||||
| 	        SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	        SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; | ||||
| 	        ExistingNotes.push_back(ii); | ||||
| 	    } | ||||
|         return true; | ||||
| @@ -457,13 +438,13 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); | ||||
| 	} | ||||
|  | ||||
| 	bool ProfileAction::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"resource",resource); | ||||
| 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: ProfileAction" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -477,7 +458,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj,"notes", notes); | ||||
| 	} | ||||
|  | ||||
| 	bool SecurityProfile::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"id",id); | ||||
| 			field_from_json(Obj,"name",name); | ||||
| @@ -487,7 +468,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 			field_from_json(Obj,"notes",notes); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: SecurityProfile" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -496,12 +477,12 @@ namespace OpenWifi::SecurityObjects { | ||||
| 		field_to_json(Obj, "profiles", profiles); | ||||
| 	} | ||||
|  | ||||
| 	bool SecurityProfileList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"profiles",profiles); | ||||
| 			return true; | ||||
| 		} catch(...) { | ||||
|             std::cout << "Cannot parse: SecurityProfileList" << std::endl; | ||||
|  | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -522,7 +503,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"userAction",userAction); | ||||
| 	} | ||||
|  | ||||
|     bool ActionLink::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"id",id); | ||||
| 	        field_from_json(Obj,"action",action); | ||||
| @@ -539,7 +520,7 @@ namespace OpenWifi::SecurityObjects { | ||||
|             field_from_json(Obj,"userAction",userAction); | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|             std::cout << "Cannot parse: ActionLink" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -550,14 +531,14 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"data",data); | ||||
| 	} | ||||
|  | ||||
|     bool Preferences::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool Preferences::from_json(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; | ||||
| 	} | ||||
| @@ -569,7 +550,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	    field_to_json(Obj,"email",email); | ||||
| 	} | ||||
|  | ||||
|     bool SubMfaConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool SubMfaConfig::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
| 	    try { | ||||
| 	        field_from_json(Obj,"id",id); | ||||
| 	        field_from_json(Obj,"type",type); | ||||
| @@ -577,7 +558,7 @@ namespace OpenWifi::SecurityObjects { | ||||
| 	        field_from_json(Obj,"email",email); | ||||
| 	        return true; | ||||
| 	    } catch(...) { | ||||
|             std::cout << "Cannot parse: SubMfaConfig" << std::endl; | ||||
|  | ||||
| 	    } | ||||
| 	    return false; | ||||
| 	} | ||||
| @@ -591,10 +572,9 @@ namespace OpenWifi::SecurityObjects { | ||||
|         field_to_json(Obj,"expires",expires); | ||||
|         field_to_json(Obj,"idleTimeout",idleTimeout); | ||||
|         field_to_json(Obj,"revocationDate",revocationDate); | ||||
|         field_to_json(Obj,"lastRefresh", lastRefresh); | ||||
|     } | ||||
|  | ||||
|     bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|     bool Token::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj,"token",token); | ||||
|             field_from_json(Obj,"refreshToken",refreshToken); | ||||
| @@ -604,10 +584,9 @@ namespace OpenWifi::SecurityObjects { | ||||
|             field_from_json(Obj,"expires",expires); | ||||
|             field_from_json(Obj,"idleTimeout",idleTimeout); | ||||
|             field_from_json(Obj,"revocationDate",revocationDate); | ||||
|             field_from_json(Obj,"lastRefresh", lastRefresh); | ||||
|             return true; | ||||
|         } catch(...) { | ||||
|             std::cout << "Cannot parse: Token" << std::endl; | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|   | ||||
| @@ -9,14 +9,12 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "Poco/JSON/Object.h" | ||||
| #include "Poco/Data/LOB.h" | ||||
| #include "Poco/Data/LOBStream.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     uint64_t Now(); | ||||
|     namespace SecurityObjects { | ||||
|  | ||||
|         typedef std::string USER_ID_TYPE; | ||||
| @@ -28,13 +26,8 @@ namespace OpenWifi { | ||||
|             bool Delete_ = true; | ||||
|             bool PortalLogin_ = true; | ||||
|  | ||||
|             AclTemplate()  noexcept = default; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         static_assert( std::is_nothrow_move_constructible_v<AclTemplate> ); | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; | ||||
|  | ||||
|         struct WebToken { | ||||
|             std::string access_token_; | ||||
| @@ -48,7 +41,6 @@ namespace OpenWifi { | ||||
|             uint64_t idle_timeout_=0; | ||||
|             AclTemplate acl_template_; | ||||
|             uint64_t created_=0; | ||||
|             uint64_t lastRefresh_=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -62,12 +54,11 @@ namespace OpenWifi { | ||||
|         std::string UserTypeToString(USER_ROLE U); | ||||
|  | ||||
|         struct NoteInfo { | ||||
|             uint64_t    created=0; // = OpenWifi::Now(); | ||||
|             uint64_t created = std::time(nullptr); | ||||
|             std::string createdBy; | ||||
|             std::string note; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<NoteInfo>	NoteInfoVec; | ||||
|  | ||||
| @@ -77,7 +68,7 @@ namespace OpenWifi { | ||||
|             bool primary = false; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MfaAuthInfo { | ||||
| @@ -85,7 +76,7 @@ namespace OpenWifi { | ||||
|             std::string method; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UserLoginLoginExtensions { | ||||
| @@ -94,17 +85,17 @@ namespace OpenWifi { | ||||
|             std::string                     authenticatorSecret; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MFAChallengeRequest { | ||||
|             std::string uuid; | ||||
|             std::string question; | ||||
|             std::string method; | ||||
|             uint64_t    created = OpenWifi::Now(); | ||||
|             uint64_t    created = std::time(nullptr); | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct MFAChallengeResponse { | ||||
| @@ -112,7 +103,7 @@ namespace OpenWifi { | ||||
|             std::string answer; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct UserInfo { | ||||
| @@ -147,20 +138,12 @@ namespace OpenWifi { | ||||
|             std::string oauthType; | ||||
|             std::string oauthUserInfo; | ||||
|             uint64_t    modified; | ||||
|             std::string signingUp; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<UserInfo>   UserInfoVec; | ||||
|  | ||||
|         struct UserInfoList { | ||||
|             std::vector<UserInfo>   users; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||
|         bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||
|         bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); | ||||
| @@ -224,7 +207,7 @@ namespace OpenWifi { | ||||
|             std::string resource; | ||||
|             ResourceAccessType access; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|         typedef std::vector<ProfileAction>	ProfileActionVec; | ||||
|  | ||||
| @@ -236,23 +219,21 @@ namespace OpenWifi { | ||||
|             std::string role; | ||||
|             NoteInfoVec notes; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(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); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         enum LinkActions { | ||||
|             FORGOT_PASSWORD=1, | ||||
|             VERIFY_EMAIL, | ||||
|             SUB_FORGOT_PASSWORD, | ||||
|             SUB_VERIFY_EMAIL, | ||||
|             SUB_SIGNUP, | ||||
|             EMAIL_INVITATION | ||||
|             SUB_VERIFY_EMAIL | ||||
|         }; | ||||
|  | ||||
|         struct ActionLink { | ||||
| @@ -264,14 +245,14 @@ namespace OpenWifi { | ||||
|             std::string         locale; | ||||
|             std::string         message; | ||||
|             uint64_t            sent=0; | ||||
|             uint64_t            created=OpenWifi::Now(); | ||||
|             uint64_t            created=std::time(nullptr); | ||||
|             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); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Preferences { | ||||
| @@ -279,7 +260,7 @@ namespace OpenWifi { | ||||
|             uint64_t                            modified; | ||||
|             Types::StringPairVec                data; | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct SubMfaConfig { | ||||
| @@ -289,7 +270,7 @@ namespace OpenWifi { | ||||
|             std::string                         email; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Token { | ||||
| @@ -301,10 +282,9 @@ namespace OpenWifi { | ||||
|             uint64_t            expires=0; | ||||
|             uint64_t            idleTimeout=0; | ||||
|             uint64_t            revocationDate=0; | ||||
|             uint64_t            lastRefresh=0; | ||||
|  | ||||
|             void to_json(Poco::JSON::Object &Obj) const; | ||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||
|         }; | ||||
|  | ||||
|         struct Avatar { | ||||
| @@ -312,7 +292,7 @@ namespace OpenWifi { | ||||
|             std::string             type; | ||||
|             uint64_t                created=0; | ||||
|             std::string             name; | ||||
|             Poco::Data::BLOB        avatar; | ||||
|             Poco::Data::LOB<char>   avatar; | ||||
|         }; | ||||
|  | ||||
|         struct LoginRecordInfo { | ||||
|   | ||||
| @@ -280,7 +280,6 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "ipv6", ipv6); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|         field_to_json(Obj, "manufacturer", manufacturer); | ||||
|     } | ||||
|  | ||||
|     bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -294,7 +293,6 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "ipv6", ipv6); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             field_from_json(Obj, "manufacturer", manufacturer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -326,7 +324,6 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "ipv6", ipv6); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|         field_to_json(Obj, "manufacturer", manufacturer); | ||||
|     } | ||||
|  | ||||
|     bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -338,7 +335,6 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "ipv6", ipv6); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             field_from_json(Obj, "manufacturer", manufacturer); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -437,8 +433,6 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "rates", rates); | ||||
|         field_to_json(Obj, "he", he); | ||||
|         field_to_json(Obj, "rawInfo", rawInfo); | ||||
|         field_to_json(Obj, "allowDFS", allowDFS); | ||||
|         field_to_json(Obj, "mimo", mimo); | ||||
|     } | ||||
|  | ||||
|     bool RadioInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| @@ -458,8 +452,6 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "rates", rates); | ||||
|             field_from_json(Obj, "he", he); | ||||
|             field_from_json(Obj, "rawInfo", rawInfo); | ||||
|             field_from_json(Obj, "allowDFS", allowDFS); | ||||
|             field_from_json(Obj, "mimo", mimo); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -469,7 +461,6 @@ namespace OpenWifi::SubObjects { | ||||
|     void AccessPoint::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "id", id); | ||||
|         field_to_json(Obj, "macAddress", macAddress); | ||||
|         field_to_json(Obj, "serialNumber", serialNumber); | ||||
|         field_to_json(Obj, "name", name); | ||||
|         field_to_json(Obj, "deviceType", deviceType); | ||||
|         field_to_json(Obj, "subscriberDevices", subscriberDevices); | ||||
| @@ -482,19 +473,12 @@ namespace OpenWifi::SubObjects { | ||||
|         field_to_json(Obj, "radios", radios); | ||||
|         field_to_json(Obj, "automaticUpgrade", automaticUpgrade); | ||||
|         field_to_json(Obj, "configurationUUID", configurationUUID); | ||||
|         field_to_json(Obj, "currentFirmware", currentFirmware); | ||||
|         field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|         field_to_json(Obj, "latestFirmware", latestFirmware); | ||||
|         field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|         field_to_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); | ||||
|         field_to_json(Obj, "latestFirmwareURI", latestFirmwareURI); | ||||
|     } | ||||
|  | ||||
|     bool AccessPoint::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "id", id); | ||||
|             field_from_json(Obj, "macAddress", macAddress); | ||||
|             field_from_json(Obj, "serialNumber", serialNumber); | ||||
|             field_from_json(Obj, "name", name); | ||||
|             field_from_json(Obj, "deviceType", deviceType); | ||||
|             field_from_json(Obj, "subscriberDevices", subscriberDevices); | ||||
| @@ -507,12 +491,6 @@ namespace OpenWifi::SubObjects { | ||||
|             field_from_json(Obj, "radios", radios); | ||||
|             field_from_json(Obj, "automaticUpgrade", automaticUpgrade); | ||||
|             field_from_json(Obj, "configurationUUID", configurationUUID); | ||||
|             field_from_json(Obj, "currentFirmware", currentFirmware); | ||||
|             field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); | ||||
|             field_from_json(Obj, "latestFirmware", latestFirmware); | ||||
|             field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); | ||||
|             field_from_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); | ||||
|             field_from_json(Obj, "latestFirmwareURI", latestFirmwareURI); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -566,38 +544,4 @@ namespace OpenWifi::SubObjects { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void StatsEntry::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "timestamp", timestamp); | ||||
|         field_to_json(Obj, "tx", tx); | ||||
|         field_to_json(Obj, "rx", rx); | ||||
|     } | ||||
|  | ||||
|     bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "timestamp", timestamp); | ||||
|             field_from_json(Obj, "tx", tx); | ||||
|             field_from_json(Obj, "rx", rx); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void StatsBlock::to_json(Poco::JSON::Object &Obj) const { | ||||
|         field_to_json(Obj, "modified", modified); | ||||
|         field_to_json(Obj, "external", external); | ||||
|         field_to_json(Obj, "internal", internal); | ||||
|     } | ||||
|  | ||||
|     bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|         try { | ||||
|             field_from_json(Obj, "modified", modified); | ||||
|             field_from_json(Obj, "external", external); | ||||
|             field_from_json(Obj, "internal", internal); | ||||
|             return true; | ||||
|         } catch (...) { | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -24,7 +24,6 @@ namespace OpenWifi::SubObjects { | ||||
|         int             subnetMaskV6=0; | ||||
|         std::string     startIPV6; | ||||
|         std::string     endIPV6; | ||||
|         std::string     leaseTime; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -157,7 +156,6 @@ namespace OpenWifi::SubObjects { | ||||
|         std::string     ipv6; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|         std::string     manufacturer; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -180,7 +178,6 @@ namespace OpenWifi::SubObjects { | ||||
|         std::string     ipv6; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|         std::string     manufacturer; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -241,8 +238,6 @@ namespace OpenWifi::SubObjects { | ||||
|         uint64_t                maximumClients = 64; | ||||
|         RadioRates              rates; | ||||
|         RadioHE                 he; | ||||
|         bool                    allowDFS=false; | ||||
|         std::string             mimo; | ||||
|         std::vector<std::string>    rawInfo; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
| @@ -252,7 +247,6 @@ namespace OpenWifi::SubObjects { | ||||
|     struct AccessPoint { | ||||
|         std::string                 id; | ||||
|         std::string                 macAddress; | ||||
|         std::string                 serialNumber; | ||||
|         std::string                 name; | ||||
|         std::string                 deviceType; | ||||
|         SubscriberDeviceList        subscriberDevices; | ||||
| @@ -265,12 +259,6 @@ namespace OpenWifi::SubObjects { | ||||
|         std::vector<RadioInformation>   radios; | ||||
|         bool                        automaticUpgrade = true; | ||||
|         std::string                 configurationUUID; | ||||
|         std::string                 currentFirmware; | ||||
|         uint64_t                    currentFirmwareDate; | ||||
|         std::string                 latestFirmware; | ||||
|         uint64_t                    latestFirmwareDate; | ||||
|         bool                        newFirmwareAvailable; | ||||
|         std::string                 latestFirmwareURI; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| @@ -300,23 +288,6 @@ namespace OpenWifi::SubObjects { | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct StatsEntry { | ||||
|         uint64_t        timestamp=0; | ||||
|         uint64_t        tx=0; | ||||
|         uint64_t        rx=0; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
|  | ||||
|     struct StatsBlock { | ||||
|         uint64_t                    modified=0; | ||||
|         std::vector<StatsEntry>     external, internal; | ||||
|  | ||||
|         void to_json(Poco::JSON::Object &Obj) const; | ||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #endif //OWSUB_RESTAPI_SUBOBJECTS_H | ||||
|   | ||||
| @@ -34,7 +34,7 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void SMSSender::CleanCache() { | ||||
|         uint64_t Now=OpenWifi::Now(); | ||||
|         uint64_t Now=std::time(nullptr); | ||||
|         for(auto i=begin(Cache_);i!=end(Cache_);) { | ||||
|             if((Now-i->Created)>300) | ||||
|                 i = Cache_.erase(i); | ||||
| @@ -45,10 +45,8 @@ namespace OpenWifi { | ||||
|  | ||||
|     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|         CleanCache(); | ||||
|         uint64_t Now=OpenWifi::Now(); | ||||
|         uint64_t Now=std::time(nullptr); | ||||
|         auto Challenge = MFAServer::MakeChallenge(); | ||||
|         Cache_.emplace_back(SMSValidationCacheEntry{.Number=Number, .Code=Challenge, .UserName=UserName, .Created=Now}); | ||||
|         std::string Message = "Please enter the following code on your login screen: " + Challenge; | ||||
| @@ -58,9 +56,6 @@ namespace OpenWifi { | ||||
|     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|  | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|  | ||||
|         for(const auto &i:Cache_) { | ||||
|             if(i.Number==Number && i.UserName==UserName) | ||||
|                 return i.Validated; | ||||
| @@ -71,9 +66,6 @@ namespace OpenWifi { | ||||
|     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { | ||||
|         std::lock_guard     G(Mutex_); | ||||
|  | ||||
|         if(!Enabled_) | ||||
|             return false; | ||||
|  | ||||
|         for(auto &i:Cache_) { | ||||
|             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { | ||||
|                 i.Validated=true; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | ||||
|         std::string Number; | ||||
|         std::string Code; | ||||
|         std::string UserName; | ||||
|         uint64_t    Created = OpenWifi::Now(); | ||||
|         uint64_t    Created = std::time(nullptr); | ||||
|         bool        Validated = false; | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -51,16 +51,16 @@ namespace OpenWifi { | ||||
|  | ||||
|             auto psms_out = sns.Publish(psms_req); | ||||
|             if (psms_out.IsSuccess()) { | ||||
|                 Logger().debug(fmt::format("SMS sent to {}",PhoneNumber)); | ||||
|                 Logger().debug(Poco::format("SMS sent to %s",PhoneNumber)); | ||||
|                 return true; | ||||
|             } | ||||
|             std::string ErrMsg{psms_out.GetError().GetMessage()}; | ||||
|             Logger().debug(fmt::format("SMS NOT sent to {}: {}",PhoneNumber, ErrMsg)); | ||||
|             Logger().debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); | ||||
|             return false; | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         Logger().debug(fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber)); | ||||
|         Logger().debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -54,7 +54,7 @@ namespace OpenWifi { | ||||
|  | ||||
|         form.add("To",PhoneNumber); | ||||
|         form.add("From",PhoneNumber_); | ||||
|         form.add("Body", Message); | ||||
|         form.add("Body","This is from twillio"); | ||||
|  | ||||
|         form.prepareSubmit(req); | ||||
|         std::ostream& ostr = session.sendRequest(req); | ||||
| @@ -64,12 +64,12 @@ namespace OpenWifi { | ||||
|         std::istream& rs = session.receiveResponse(res); | ||||
|  | ||||
|         if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||
|             Logger().information(fmt::format("Message sent to {}", PhoneNumber)); | ||||
|             Logger().information(Poco::format("Message sent to %s", PhoneNumber)); | ||||
|             return true; | ||||
|         } else { | ||||
|             std::ostringstream os; | ||||
|             Poco::StreamCopier::copyStream(rs,os); | ||||
|             Logger().information(fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str())); | ||||
|             Logger().information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str())); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -12,7 +12,6 @@ | ||||
| #include "Poco/Exception.h" | ||||
| #include "Poco/Net/SSLManager.h" | ||||
| #include "Poco/Net/Context.h" | ||||
| #include "Poco/Net/NetException.h" | ||||
|  | ||||
| #include "SMTPMailerService.h" | ||||
| #include "framework/MicroService.h" | ||||
| @@ -28,13 +27,11 @@ namespace OpenWifi { | ||||
|             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); | ||||
|             Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); | ||||
|             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); | ||||
|             MailHostPort_ = MicroService::instance().ConfigGetInt("mailer.port"); | ||||
|             MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); | ||||
|             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); | ||||
|             MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||
|             MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||
|             UseHTML_ = MicroService::instance().ConfigGetBool("mailer.html",false); | ||||
|             MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||
|             MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||
|             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||
|             EmailLogo_ = TemplateDir_ + "/" + MicroService::instance().ConfigGetString("mailer.logo","logo.jpg"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -50,25 +47,24 @@ namespace OpenWifi { | ||||
|         SenderThr_.join(); | ||||
|     } | ||||
|  | ||||
|     void SMTPMailerService::reinitialize([[maybe_unused]] Poco::Util::Application &self) { | ||||
|     void SMTPMailerService::reinitialize(Poco::Util::Application &self) { | ||||
|         MicroService::instance().LoadConfigurationFile(); | ||||
|         Logger().information("Reinitializing."); | ||||
|         LoadMyConfig(); | ||||
|     } | ||||
|  | ||||
|     bool SMTPMailerService::SendMessage([[maybe_unused]] const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { | ||||
|     bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { | ||||
|         std::lock_guard G(Mutex_); | ||||
|         PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(), | ||||
|         PendingMessages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr), | ||||
|                                             .LastTry=0, | ||||
|                                             .Sent=0, | ||||
|                                             .TemplateName=Name, | ||||
|                                             .File=Poco::File(TemplateDir_ + "/" +Name), | ||||
|                                             .Attrs=Attrs}); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void SMTPMailerService::run() { | ||||
|         Running_ = true; | ||||
|         Utils::SetThreadName("smtp-mailer"); | ||||
|         while(Running_) { | ||||
|  | ||||
|             Poco::Thread::trySleep(10000); | ||||
| @@ -84,25 +80,17 @@ namespace OpenWifi { | ||||
|                 if(!Running_) | ||||
|                     break; | ||||
|                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|                 uint64_t now = OpenWifi::Now(); | ||||
|                 if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) { | ||||
|                     switch(SendIt(*i)) { | ||||
|                         case MessageSendStatus::msg_sent: { | ||||
|                             Logger().information(fmt::format("Attempting to deliver for mail '{}'.", Recipient)); | ||||
|                 uint64_t Now = std::time(nullptr); | ||||
|                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { | ||||
|                     if (SendIt(*i)) { | ||||
|                         Logger().information(Poco::format("Attempting to deliver for mail '%s'.", Recipient)); | ||||
|                         i = Messages_.erase(i); | ||||
|                         } break; | ||||
|                         case MessageSendStatus::msg_not_sent_but_resend: { | ||||
|                             Logger().information(fmt::format("Mail for '{}' was not. We will retry later.", Recipient)); | ||||
|                             i->LastTry = now; | ||||
|                     } else { | ||||
|                         i->LastTry = Now; | ||||
|                         ++i; | ||||
|                         } break; | ||||
|                         case MessageSendStatus::msg_not_sent_but_do_not_resend: { | ||||
|                             Logger().information(fmt::format("Mail for '{}' will not be sent. Check email address", Recipient)); | ||||
|                             i = Messages_.erase(i); | ||||
|                         } break; | ||||
|                     } | ||||
|                 } else if ((now-i->Posted)>MailAbandon_) { | ||||
|                     Logger().information(fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient)); | ||||
|                 } else if ((Now-i->Posted)>MailAbandon_) { | ||||
|                     Logger().information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient)); | ||||
|                     i = Messages_.erase(i); | ||||
|                 } else { | ||||
|                     ++i; | ||||
| @@ -117,12 +105,14 @@ namespace OpenWifi { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     MessageSendStatus SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||
|  | ||||
|     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||
|         std::string             Recipient; | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             Poco::Net::MailMessage  Message; | ||||
|             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|  | ||||
|             auto H1 = Msg.Attrs.find(SENDER); | ||||
|             std::string TheSender; | ||||
|             if(H1!=Msg.Attrs.end()) { | ||||
| @@ -130,40 +120,32 @@ namespace OpenWifi { | ||||
|             } else { | ||||
|                 TheSender = Sender_ ; | ||||
|             } | ||||
|  | ||||
|             auto Message = std::make_unique<Poco::Net::MailMessage>(); | ||||
|  | ||||
|             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||
|             Message->setSender( TheSender ); | ||||
|             Message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||
|             Message->setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||
|  | ||||
|             Logger().information(fmt::format("Sending message to:{} from {}",Recipient,TheSender)); | ||||
|             Message.setSender( TheSender ); | ||||
|             Logger().information(Poco::format("Sending message to:%s from %s",Recipient,TheSender)); | ||||
|             Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||
|  | ||||
|             if(Msg.Attrs.find(TEXT) != Msg.Attrs.end()) { | ||||
|                 std::string Content = Msg.Attrs.find(TEXT)->second; | ||||
|                 Message->addContent(new Poco::Net::StringPartSource(Content)); | ||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||
|             } else { | ||||
|                 for(const auto &format:{"html","txt"}) { | ||||
|                     std::string Content = Utils::LoadFile(TemplateDir_ + Msg.TemplateName + "." + format ); | ||||
|                 std::string Content = Utils::LoadFile(Msg.File); | ||||
|                 Types::StringPairVec    Variables; | ||||
|                 FillVariables(Msg.Attrs, Variables); | ||||
|                 Utils::ReplaceVariables(Content, Variables); | ||||
|                     Message->addContent( | ||||
|                             new Poco::Net::StringPartSource(Content, (strcmp(format,"html") == 0 ? "text/html" : "text/plain") )); | ||||
|                 } | ||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); | ||||
|             } | ||||
|  | ||||
|             auto Logo = Msg.Attrs.find(LOGO); | ||||
|             if(Logo!=Msg.Attrs.end()) { | ||||
|                 try { | ||||
|                     Poco::File          LogoFile(EmailLogo_); | ||||
|                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); | ||||
|                     std::ifstream       IF(LogoFile.path()); | ||||
|                     std::ostringstream  OS; | ||||
|                     Poco::StreamCopier::copyStream(IF, OS); | ||||
|                     Message->addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||
|                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||
|                 } catch (...) { | ||||
|                     Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName())); | ||||
|                     Logger().warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -184,23 +166,18 @@ namespace OpenWifi { | ||||
|                           SenderLoginUserName_, | ||||
|                           SenderLoginPassword_ | ||||
|             ); | ||||
|             session.sendMessage(*Message); | ||||
|             session.sendMessage(Message); | ||||
|             session.close(); | ||||
|             return MessageSendStatus::msg_sent; | ||||
|         } | ||||
|         catch (const Poco::Net::SMTPException &S) { | ||||
|             Logger().log(S); | ||||
|             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||
|             return true; | ||||
|         } | ||||
|         catch (const Poco::Exception& E) | ||||
|         { | ||||
|             Logger().log(E); | ||||
|             return MessageSendStatus::msg_not_sent_but_resend; | ||||
|         } | ||||
|         catch (const std::exception &E) { | ||||
|             Logger().warning(fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what())); | ||||
|             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||
|             Logger().warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what())); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -27,8 +27,7 @@ namespace OpenWifi { | ||||
|         LOGO, | ||||
|         TEXT, | ||||
|         CHALLENGE_CODE, | ||||
|         SENDER, | ||||
|         ACTION_LINK_HTML | ||||
|         SENDER | ||||
|     }; | ||||
|  | ||||
|     static const std::map<MESSAGE_ATTRIBUTES,const std::string> | ||||
| @@ -45,8 +44,7 @@ namespace OpenWifi { | ||||
|                                  {  LOGO, "LOGO"}, | ||||
|                                  {  TEXT, "TEXT"}, | ||||
|                                  {  CHALLENGE_CODE, "CHALLENGE_CODE"}, | ||||
|                                  {  SENDER, "SENDER"}, | ||||
|                                  {  ACTION_LINK_HTML, "ACTION_LINK_HTML"}, | ||||
|                                  {  SENDER, "SENDER"} | ||||
|                                  }; | ||||
|  | ||||
|     inline const std::string & MessageAttributeToVar(MESSAGE_ATTRIBUTES Attr) { | ||||
| @@ -58,12 +56,6 @@ namespace OpenWifi { | ||||
|     } | ||||
|     typedef std::map<MESSAGE_ATTRIBUTES, std::string>   MessageAttributes; | ||||
|  | ||||
|     enum class MessageSendStatus { | ||||
|         msg_sent, | ||||
|         msg_not_sent_but_resend, | ||||
|         msg_not_sent_but_do_not_resend | ||||
|     }; | ||||
|  | ||||
|     class SMTPMailerService : public SubSystemServer, Poco::Runnable { | ||||
|         public: | ||||
|            static SMTPMailerService *instance() { | ||||
| @@ -75,7 +67,7 @@ namespace OpenWifi { | ||||
|                uint64_t             Posted=0; | ||||
|                uint64_t             LastTry=0; | ||||
|                uint64_t             Sent=0; | ||||
|                std::string          TemplateName; | ||||
|                Poco::File           File; | ||||
|                MessageAttributes    Attrs; | ||||
|             }; | ||||
|  | ||||
| @@ -84,7 +76,7 @@ namespace OpenWifi { | ||||
|             void Stop() override; | ||||
|  | ||||
|             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); | ||||
|             MessageSendStatus SendIt(const MessageEvent &Msg); | ||||
|             bool SendIt(const MessageEvent &Msg); | ||||
|             void LoadMyConfig(); | ||||
|             void reinitialize(Poco::Util::Application &self) override; | ||||
|             bool Enabled() const { return Enabled_; } | ||||
| @@ -92,9 +84,9 @@ namespace OpenWifi { | ||||
|         private: | ||||
|             std::string             MailHost_; | ||||
|             std::string             Sender_; | ||||
|             uint32_t                MailHostPort_=25; | ||||
|             uint64_t                MailRetry_=2*60; | ||||
|             uint64_t                MailAbandon_=2*60*20; | ||||
|             int                     MailHostPort_=25; | ||||
|             int                     MailRetry_=2*60; | ||||
|             int                     MailAbandon_=2*60*20; | ||||
|             std::string             SenderLoginUserName_; | ||||
|             std::string             SenderLoginPassword_; | ||||
|             std::string             LoginMethod_ = "login"; | ||||
| @@ -104,8 +96,6 @@ namespace OpenWifi { | ||||
|             Poco::Thread            SenderThr_; | ||||
|             std::atomic_bool        Running_=false; | ||||
|             bool                    Enabled_=false; | ||||
|             bool                    UseHTML_=false; | ||||
|             std::string             EmailLogo_{"logo.jpg"}; | ||||
|  | ||||
|             SMTPMailerService() noexcept: | ||||
|                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") | ||||
|   | ||||
| @@ -22,7 +22,7 @@ namespace OpenWifi { | ||||
|                 U.email = MicroService::instance().ConfigGetString("authentication.default.username", ""); | ||||
|                 U.id = NewDefaultUseridStockUUID; | ||||
|                 U.userRole = SecurityObjects::ROOT; | ||||
|                 U.creationDate = OpenWifi::Now(); | ||||
|                 U.creationDate = std::time(nullptr); | ||||
|                 U.validated = true; | ||||
|                 U.name = "Default User"; | ||||
|                 U.description = "Default user should be deleted."; | ||||
|   | ||||
| @@ -29,7 +29,7 @@ namespace OpenWifi { | ||||
|         PreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("Preferences", "pre", dbType_,*Pool_, Logger()); | ||||
|         SubPreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("SubPreferences", "prs", dbType_,*Pool_, Logger()); | ||||
|         ActionLinksDB_ = std::make_unique<OpenWifi::ActionLinkDB>("Actions", "act", dbType_,*Pool_, Logger()); | ||||
|         AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("Avatars2", "ava", dbType_,*Pool_, Logger()); | ||||
|         AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("Avatars", "ava", dbType_,*Pool_, Logger()); | ||||
|         SubAvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("SubAvatars", "avs", dbType_,*Pool_, Logger()); | ||||
|         LoginDB_ = std::make_unique<OpenWifi::LoginDB>("Logins", "lin", dbType_,*Pool_, Logger()); | ||||
|         SubLoginDB_ = std::make_unique<OpenWifi::LoginDB>("SubLogins", "lis", dbType_,*Pool_, Logger()); | ||||
| @@ -51,7 +51,7 @@ namespace OpenWifi { | ||||
| 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | ||||
| 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | ||||
| 		Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | ||||
| 		Timer_.start(*Archivercallback_, MicroService::instance().TimerPool()); | ||||
| 		Timer_.start(*Archivercallback_); | ||||
|  | ||||
| 		return 0; | ||||
|     } | ||||
| @@ -62,8 +62,7 @@ namespace OpenWifi { | ||||
|         StorageClass::Stop(); | ||||
|     } | ||||
|  | ||||
|     void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||
|         Utils::SetThreadName("strg-arch"); | ||||
|     void Archiver::onTimer(Poco::Timer &timer) { | ||||
|         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); | ||||
|         logger.information("Squiggy the DB: removing old tokens."); | ||||
|         StorageService()->SubTokenDB().CleanExpiredTokens(); | ||||
|   | ||||
| @@ -41,6 +41,7 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { | ||||
|  | ||||
|             std::string uri{ | ||||
|                 "otpauth://totp/" + Issuer_ + ":" + | ||||
|                 email + "?secret=" + Secret + "&issuer=" + Issuer_ | ||||
| @@ -52,12 +53,12 @@ namespace OpenWifi { | ||||
|         } | ||||
|  | ||||
|         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { | ||||
|             uint64_t Now = OpenWifi::Now(); | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6); | ||||
|             char buffer[16]{0}; | ||||
|             char buffer[16]; | ||||
|             sprintf(buffer,"%06u",p); | ||||
|             Expecting = std::string(buffer); | ||||
|             return Code == Expecting; | ||||
|             Expecting = buffer; | ||||
|             return Code == buffer; | ||||
|         } | ||||
|  | ||||
|         int Start() override { | ||||
| @@ -75,7 +76,7 @@ namespace OpenWifi { | ||||
|                 if(Reset) { | ||||
|                     std::string Base32Secret; | ||||
|                     Hint->second.Subscriber = Subscriber; | ||||
|                     Hint->second.Start = OpenWifi::Now(); | ||||
|                     Hint->second.Start = std::time(nullptr); | ||||
|                     Hint->second.Done = 0; | ||||
|                     Hint->second.Verifications = 0; | ||||
|                     Hint->second.Secret = GenerateSecret(20,Base32Secret); | ||||
| @@ -92,21 +93,21 @@ namespace OpenWifi { | ||||
|             QRCode = GenerateQRCode(Base32Secret, User.email); | ||||
|  | ||||
|             Entry E{ .Subscriber = Subscriber, | ||||
|                      .Start = OpenWifi::Now(), | ||||
|                      .Start = (uint64_t )std::time(nullptr), | ||||
|                      .Done = 0, | ||||
|                      .Verifications = 0, | ||||
|                      .Secret = Secret, | ||||
|                      .QRCode = QRCode, | ||||
|                      .LastCode = "" | ||||
|                      .QRCode = QRCode | ||||
|                      }; | ||||
|             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 ) { | ||||
|                                        uint64_t &NextIndex, bool &MoreCodes, uint64_t & ErrorCode, std::string & ErrorText ) { | ||||
|             auto Hint = Cache_.find(User.id); | ||||
|             uint64_t Now = OpenWifi::Now(); | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             ErrorCode = 0; | ||||
|             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)) { | ||||
| @@ -122,27 +123,32 @@ namespace OpenWifi { | ||||
|                     return true; | ||||
|                 } else { | ||||
|                     if(!ValidateCode(Hint->second.Secret, Code, Expecting)) { | ||||
|                         Error = RESTAPI::Errors::TOTInvalidCode; | ||||
|                         ErrorCode = 1; | ||||
|                         ErrorText = "Invalid code."; | ||||
|                         return false; | ||||
|                     } else if(NextIndex!=1 && NextIndex != 2) { | ||||
|                         Error = RESTAPI::Errors::TOTInvalidIndex; | ||||
|                         ErrorCode = 2; | ||||
|                         ErrorText = "Invalid Index"; | ||||
|                         return false; | ||||
|                     } else if(Code == Hint->second.LastCode) { | ||||
|                         Error = RESTAPI::Errors::TOTRepeatedCode; | ||||
|                         ErrorCode = 3; | ||||
|                         ErrorText = "Code is repeated. Must be new code."; | ||||
|                         return false; | ||||
|                     } | ||||
|                     Error = RESTAPI::Errors::TOTInvalidProtocol; | ||||
|                     ErrorCode = 5; | ||||
|                     ErrorText = "Invalid protocol sequence."; | ||||
|                     return false; | ||||
|                 } | ||||
|             } else { | ||||
|                 Error = RESTAPI::Errors::TOTNoSession; | ||||
|                 ErrorCode = 4; | ||||
|                 ErrorText = "No validation session present."; | ||||
|             } | ||||
|             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(); | ||||
|             uint64_t Now = std::time(nullptr); | ||||
|             if(Hint!=Cache_.end() && Subscriber==Hint->second.Subscriber && (Now-Hint->second.Start)<(15*60) && Hint->second.Done!=0) { | ||||
|                 Secret = Hint->second.Secret; | ||||
|                 Cache_.erase(Hint); | ||||
|   | ||||
| @@ -13,11 +13,9 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| static const std::string GitUCentralJSONSchemaFile{ | ||||
| 	"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||
|     static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||
|  | ||||
|     static json DefaultUCentralSchema = R"( | ||||
|  | ||||
| { | ||||
|     "$id": "https://openwrt.org/ucentral.schema.json", | ||||
|     "$schema": "http://json-schema.org/draft-07/schema#", | ||||
| @@ -77,10 +75,6 @@ static json DefaultUCentralSchema = R"( | ||||
|                 "name": { | ||||
|                     "type": "string" | ||||
|                 }, | ||||
| 				"hostname": { | ||||
| 					"type": "string", | ||||
| 					"format": "hostname" | ||||
| 				}, | ||||
|                 "location": { | ||||
|                     "type": "string" | ||||
|                 }, | ||||
| @@ -107,14 +101,12 @@ static json DefaultUCentralSchema = R"( | ||||
|             "items": { | ||||
|                 "type": "string", | ||||
|                 "enum": [ | ||||
| 					"CS0", | ||||
|                     "CS1", | ||||
|                     "CS2", | ||||
|                     "CS3", | ||||
|                     "CS4", | ||||
|                     "CS5", | ||||
|                     "CS6", | ||||
| 					"CS7", | ||||
|                     "AF11", | ||||
|                     "AF12", | ||||
|                     "AF13", | ||||
| @@ -128,15 +120,12 @@ static json DefaultUCentralSchema = R"( | ||||
|                     "AF42", | ||||
|                     "AF43", | ||||
|                     "DF", | ||||
| 					"EF", | ||||
| 					"VA", | ||||
| 					"LE" | ||||
|                     "EF" | ||||
|                 ] | ||||
|             } | ||||
|         }, | ||||
| 		"globals.wireless-multimedia.table": { | ||||
|         "globals.wireless-multimedia": { | ||||
|             "type": "object", | ||||
| 			"additionalProperties": false, | ||||
|             "properties": { | ||||
|                 "UP0": { | ||||
|                     "$ref": "#/$defs/globals.wireless-multimedia.class-selector" | ||||
| @@ -164,19 +153,11 @@ static json DefaultUCentralSchema = R"( | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
| 		"globals.wireless-multimedia.profile": { | ||||
| 			"type": "object", | ||||
| 			"additionalProperties": false, | ||||
| 			"properties": { | ||||
| 				"profile": { | ||||
|         "globals.wireless-multimedia-profile": { | ||||
|             "type": "string", | ||||
|             "enum": [ | ||||
| 						"enterprise", | ||||
| 						"rfc8325", | ||||
| 						"3gpp" | ||||
|                 "enterprise" | ||||
|             ] | ||||
| 				} | ||||
| 			} | ||||
|         }, | ||||
|         "globals": { | ||||
|             "type": "object", | ||||
| @@ -196,11 +177,12 @@ static json DefaultUCentralSchema = R"( | ||||
|                     ] | ||||
|                 }, | ||||
|                 "wireless-multimedia": { | ||||
| 					"anyOf": [{ | ||||
| 							"$ref": "#/$defs/globals.wireless-multimedia.table" | ||||
|                     "oneOf": [ | ||||
|                         { | ||||
|                             "$ref": "#/$defs/globals.wireless-multimedia" | ||||
|                         }, | ||||
|                         { | ||||
| 							"$ref": "#/$defs/globals.wireless-multimedia.profile" | ||||
|                             "$ref": "#/$defs/globals.wireless-multimedia-profile" | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
| @@ -390,9 +372,10 @@ static json DefaultUCentralSchema = R"( | ||||
|                     ] | ||||
|                 }, | ||||
|                 "channel": { | ||||
| 					"oneOf": [{ | ||||
|                     "oneOf": [ | ||||
|                         { | ||||
|                             "type": "integer", | ||||
| 							"maximum": 196, | ||||
|                             "maximum": 171, | ||||
|                             "minimum": 1 | ||||
|                         }, | ||||
|                         { | ||||
| @@ -401,14 +384,6 @@ static json DefaultUCentralSchema = R"( | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
| 				"valid-channels": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"type": "integer", | ||||
| 						"maximum": 196, | ||||
| 						"minimum": 1 | ||||
| 					} | ||||
| 				}, | ||||
|                 "country": { | ||||
|                     "type": "string", | ||||
|                     "maxLength": 2, | ||||
| @@ -417,10 +392,6 @@ static json DefaultUCentralSchema = R"( | ||||
|                         "US" | ||||
|                     ] | ||||
|                 }, | ||||
| 				"allow-dfs": { | ||||
| 					"type": "boolean", | ||||
| 					"default": true | ||||
| 				}, | ||||
|                 "channel-mode": { | ||||
|                     "type": "string", | ||||
|                     "enum": [ | ||||
| @@ -670,47 +641,6 @@ static json DefaultUCentralSchema = R"( | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| 		"interface.ipv4.port-forward": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| 						"tcp", | ||||
| 						"udp", | ||||
| 						"any" | ||||
| 					], | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"external-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				}, | ||||
| 				"internal-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv4", | ||||
| 					"example": "0.0.0.120" | ||||
| 				}, | ||||
| 				"internal-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"external-port", | ||||
| 				"internal-address" | ||||
| 			] | ||||
| 		}, | ||||
|     "interface.ipv4": { | ||||
|     "type": "object", | ||||
|     "properties": { | ||||
| @@ -764,12 +694,6 @@ static json DefaultUCentralSchema = R"( | ||||
|             "items": { | ||||
|                 "$ref": "#/$defs/interface.ipv4.dhcp-lease" | ||||
|             } | ||||
| 				}, | ||||
| 				"port-forward": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv4.port-forward" | ||||
| 					} | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| @@ -799,96 +723,6 @@ static json DefaultUCentralSchema = R"( | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| 		"interface.ipv6.port-forward": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"enum": [ | ||||
| 						"tcp", | ||||
| 						"udp", | ||||
| 						"any" | ||||
| 					], | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"external-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				}, | ||||
| 				"internal-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv6", | ||||
| 					"example": "::1234:abcd" | ||||
| 				}, | ||||
| 				"internal-port": { | ||||
| 					"type": [ | ||||
| 						"integer", | ||||
| 						"string" | ||||
| 					], | ||||
| 					"minimum": 0, | ||||
| 					"maximum": 65535, | ||||
| 					"format": "uc-portrange" | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"external-port", | ||||
| 				"internal-address" | ||||
| 			] | ||||
| 		}, | ||||
| 		"interface.ipv6.traffic-allow": { | ||||
| 			"type": "object", | ||||
| 			"properties": { | ||||
| 				"protocol": { | ||||
| 					"type": "string", | ||||
| 					"default": "any" | ||||
| 				}, | ||||
| 				"source-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "uc-cidr6", | ||||
| 					"example": "2001:db8:1234:abcd::/64", | ||||
| 					"default": "::/0" | ||||
| 				}, | ||||
| 				"source-ports": { | ||||
| 					"type": "array", | ||||
| 					"minItems": 1, | ||||
| 					"items": { | ||||
| 						"type": [ | ||||
| 							"integer", | ||||
| 							"string" | ||||
| 						], | ||||
| 						"minimum": 0, | ||||
| 						"maximum": 65535, | ||||
| 						"format": "uc-portrange" | ||||
| 					} | ||||
| 				}, | ||||
| 				"destination-address": { | ||||
| 					"type": "string", | ||||
| 					"format": "ipv6", | ||||
| 					"example": "::1000" | ||||
| 				}, | ||||
| 				"destination-ports": { | ||||
| 					"type": "array", | ||||
| 					"minItems": 1, | ||||
| 					"items": { | ||||
| 						"type": [ | ||||
| 							"integer", | ||||
| 							"string" | ||||
| 						], | ||||
| 						"minimum": 0, | ||||
| 						"maximum": 65535, | ||||
| 						"format": "uc-portrange" | ||||
| 					} | ||||
| 				} | ||||
| 			}, | ||||
| 			"required": [ | ||||
| 				"destination-address" | ||||
| 			] | ||||
| 		}, | ||||
|     "interface.ipv6": { | ||||
|     "type": "object", | ||||
|     "properties": { | ||||
| @@ -920,18 +754,6 @@ static json DefaultUCentralSchema = R"( | ||||
|             }, | ||||
|             "dhcpv6": { | ||||
|             "$ref": "#/$defs/interface.ipv6.dhcpv6" | ||||
| 				}, | ||||
| 				"port-forward": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv6.port-forward" | ||||
| 					} | ||||
| 				}, | ||||
| 				"traffic-allow": { | ||||
| 					"type": "array", | ||||
| 					"items": { | ||||
| 						"$ref": "#/$defs/interface.ipv6.traffic-allow" | ||||
| 					} | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| @@ -999,7 +821,8 @@ static json DefaultUCentralSchema = R"( | ||||
|     } | ||||
|     }, | ||||
|     "interface.broad-band": { | ||||
| 			"oneOf": [{ | ||||
|     "oneOf": [ | ||||
|             { | ||||
|         "$ref": "#/$defs/interface.broad-band.wwan" | ||||
|         }, | ||||
|         { | ||||
| @@ -1016,7 +839,7 @@ static json DefaultUCentralSchema = R"( | ||||
|             }, | ||||
|             "gateway-fqdn": { | ||||
|             "type": "string", | ||||
| 					"format": "uc-fqdn", | ||||
|             "format": "fqdn", | ||||
|             "default": "ucentral.splash" | ||||
|             }, | ||||
|             "max-clients": { | ||||
| @@ -1051,7 +874,6 @@ static json DefaultUCentralSchema = R"( | ||||
|                     "psk", | ||||
|                     "psk2", | ||||
|                     "psk-mixed", | ||||
| 						"psk2-radius", | ||||
|                     "wpa", | ||||
|                     "wpa2", | ||||
|                     "wpa-mixed", | ||||
| @@ -1112,10 +934,6 @@ static json DefaultUCentralSchema = R"( | ||||
|             "type": "boolean", | ||||
|             "default": false | ||||
|             }, | ||||
| 				"reduced-neighbor-reporting": { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
| 				}, | ||||
|             "lci": { | ||||
|             "type": "string" | ||||
|             }, | ||||
| @@ -1256,7 +1074,8 @@ static json DefaultUCentralSchema = R"( | ||||
|                         "minimum": 1 | ||||
|                         }, | ||||
|                         "value": { | ||||
| 								"anyOf": [{ | ||||
|                         "anyOf": [ | ||||
|                                 { | ||||
|                             "type": "integer", | ||||
|                             "maximum": 4294967295, | ||||
|                             "minimum": 0 | ||||
| @@ -1267,7 +1086,8 @@ static json DefaultUCentralSchema = R"( | ||||
|                             ] | ||||
|                     } | ||||
|                     }, | ||||
| 						"examples": [{ | ||||
|                     "examples": [ | ||||
|                             { | ||||
|                     "id": 27, | ||||
|                     "value": 900 | ||||
|                     }, | ||||
| @@ -1304,49 +1124,12 @@ static json DefaultUCentralSchema = R"( | ||||
|             "local": { | ||||
|             "$ref": "#/$defs/interface.ssid.radius.local" | ||||
|             }, | ||||
| 				"dynamic-authorization": { | ||||
| 					"type": "object", | ||||
| 					"properties": { | ||||
| 						"host": { | ||||
| 							"type": "string", | ||||
| 							"format": "uc-ip", | ||||
| 							"examples": [ | ||||
| 								"192.168.1.10" | ||||
| 							] | ||||
| 						}, | ||||
| 						"port": { | ||||
| 							"type": "integer", | ||||
| 							"maximum": 65535, | ||||
| 							"minimum": 1024, | ||||
| 							"examples": [ | ||||
| 								1812 | ||||
| 							] | ||||
| 						}, | ||||
| 						"secret": { | ||||
| 							"type": "string", | ||||
| 							"examples": [ | ||||
| 								"secret" | ||||
| 							] | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
|             "authentication": { | ||||
| 					"allOf": [{ | ||||
|             "$ref": "#/$defs/interface.ssid.radius.server" | ||||
|             }, | ||||
| 						{ | ||||
| 							"type": "object", | ||||
| 							"properties": { | ||||
| 								"mac-filter": { | ||||
| 									"type": "boolean", | ||||
| 									"default": false | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
|             "accounting": { | ||||
| 					"allOf": [{ | ||||
|             "allOf": [ | ||||
|                     { | ||||
|                 "$ref": "#/$defs/interface.ssid.radius.server" | ||||
|                 }, | ||||
|                 { | ||||
| @@ -1549,13 +1332,15 @@ static json DefaultUCentralSchema = R"( | ||||
|                                 ] | ||||
|                     } | ||||
|                     }, | ||||
| 						"examples": [{ | ||||
|                     "examples": [ | ||||
|                             { | ||||
|                     "width": 32, | ||||
|                     "height": 32, | ||||
|                     "type": "image/png", | ||||
|                     "language": "eng", | ||||
|                     "icon": "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" | ||||
| 						}] | ||||
|                             } | ||||
|                             ] | ||||
|             } | ||||
|             }, | ||||
|             "wan-metrics": { | ||||
| @@ -1682,11 +1467,6 @@ static json DefaultUCentralSchema = R"( | ||||
|             "decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | ||||
|             "type": "string" | ||||
|             }, | ||||
| 				"fils-discovery-interval": { | ||||
| 					"type": "integer", | ||||
| 					"default": 20, | ||||
| 					"maximum": 10000 | ||||
| 				}, | ||||
|             "encryption": { | ||||
|             "$ref": "#/$defs/interface.ssid.encryption" | ||||
|             }, | ||||
| @@ -1801,7 +1581,8 @@ static json DefaultUCentralSchema = R"( | ||||
|     } | ||||
|     }, | ||||
|     "interface.tunnel": { | ||||
| 			"oneOf": [{ | ||||
|     "oneOf": [ | ||||
|             { | ||||
|         "$ref": "#/$defs/interface.tunnel.mesh" | ||||
|         }, | ||||
|         { | ||||
| @@ -2007,11 +1788,6 @@ static json DefaultUCentralSchema = R"( | ||||
|             "type": "integer", | ||||
|             "minimum": 32, | ||||
|             "default": 1000 | ||||
| 				}, | ||||
| 				"priority": { | ||||
| 					"type": "integer", | ||||
| 					"minimum": 0, | ||||
| 					"default": 7 | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| @@ -2158,7 +1934,7 @@ static json DefaultUCentralSchema = R"( | ||||
|     "properties": { | ||||
|         "controller": { | ||||
|             "type": "string", | ||||
| 					"format": "uc-ip", | ||||
|             "format": "ip", | ||||
|             "example": "192.168.10.1" | ||||
|             }, | ||||
|             "datapath-description": { | ||||
| @@ -2175,11 +1951,6 @@ static json DefaultUCentralSchema = R"( | ||||
|                     ], | ||||
|                     "default": "ssl" | ||||
|                     }, | ||||
| 				"port": { | ||||
| 					"type": "integer", | ||||
| 					"maximum": 65535, | ||||
| 					"default": 6653 | ||||
| 				}, | ||||
|                     "ca-certificate": { | ||||
|             "type": "string" | ||||
|             }, | ||||
| @@ -2247,42 +2018,9 @@ static json DefaultUCentralSchema = R"( | ||||
|             "auto-channel": { | ||||
|             "type": "boolean", | ||||
|             "default": false | ||||
| 				}, | ||||
| 				"ipv6": { | ||||
| 					"type": "boolean", | ||||
| 					"default": false | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| 		"service.quality-of-service.class-selector": { | ||||
| 			"type": "string", | ||||
| 			"enum": [ | ||||
| 				"CS0", | ||||
| 				"CS1", | ||||
| 				"CS2", | ||||
| 				"CS3", | ||||
| 				"CS4", | ||||
| 				"CS5", | ||||
| 				"CS6", | ||||
| 				"CS7", | ||||
| 				"AF11", | ||||
| 				"AF12", | ||||
| 				"AF13", | ||||
| 				"AF21", | ||||
| 				"AF22", | ||||
| 				"AF23", | ||||
| 				"AF31", | ||||
| 				"AF32", | ||||
| 				"AF33", | ||||
| 				"AF41", | ||||
| 				"AF42", | ||||
| 				"AF43", | ||||
| 				"DF", | ||||
| 				"EF", | ||||
| 				"VA", | ||||
| 				"LE" | ||||
| 			] | ||||
| 		}, | ||||
|     "service.quality-of-service": { | ||||
|     "type": "object", | ||||
|     "properties": { | ||||
| @@ -2301,26 +2039,23 @@ static json DefaultUCentralSchema = R"( | ||||
|             "type": "integer", | ||||
|             "default": 0 | ||||
|             }, | ||||
| 				"bulk-detection": { | ||||
| 					"type": "object", | ||||
| 					"properties": { | ||||
| 						"dscp": { | ||||
| 							"$ref": "#/$defs/service.quality-of-service.class-selector", | ||||
| 							"default": "CS0" | ||||
| 						}, | ||||
| 						"packets-per-second": { | ||||
| 							"type": "number", | ||||
| 							"default": 0 | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
|             "classifier": { | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|                 "type": "object", | ||||
|                 "properties": { | ||||
|                     "dscp": { | ||||
| 								"$ref": "#/$defs/service.quality-of-service.class-selector", | ||||
|                         "type": "string", | ||||
|                         "enum": [ | ||||
|                                 "CS0", | ||||
|                                 "CS1", | ||||
|                                 "CS2", | ||||
|                                 "CS3", | ||||
|                                 "CS4", | ||||
|                                 "CS5", | ||||
|                                 "CS6", | ||||
|                                 "CS7" | ||||
|                                 ], | ||||
|                                 "default": "CS1" | ||||
|                                 }, | ||||
|                                 "ports": { | ||||
| @@ -2348,25 +2083,12 @@ static json DefaultUCentralSchema = R"( | ||||
|                                     "default": true | ||||
|                                 } | ||||
|                             } | ||||
| 								} | ||||
|                             }, | ||||
|                             "dns": { | ||||
|                             "type": "array", | ||||
|                             "items": { | ||||
| 									"type": "object", | ||||
| 									"properties": { | ||||
| 										"fqdn": { | ||||
|                                 "type": "string", | ||||
| 											"format": "uc-fqdn" | ||||
| 										}, | ||||
| 										"suffix-matching": { | ||||
| 											"type": "boolean", | ||||
| 											"default": true | ||||
| 										}, | ||||
| 										"reclassify": { | ||||
| 											"type": "boolean", | ||||
| 											"default": true | ||||
| 										} | ||||
|                                 "format": "fqdn" | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| @@ -2389,36 +2111,21 @@ static json DefaultUCentralSchema = R"( | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| 		"service.airtime-fairness": { | ||||
|     "service.airtime-policies": { | ||||
|     "type": "object", | ||||
|     "properties": { | ||||
| 				"voice-weight": { | ||||
| 					"type": "number", | ||||
| 					"default": 4 | ||||
|         "dns-match": { | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|                 "type": "string", | ||||
|                 "examples": [ | ||||
|                         "*.voice.example.com" | ||||
|                         ] | ||||
|             } | ||||
|             }, | ||||
| 				"packet-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 100 | ||||
| 				}, | ||||
| 				"bulk-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 50 | ||||
| 				}, | ||||
| 				"priority-threshold": { | ||||
| 					"type": "number", | ||||
| 					"default": 30 | ||||
| 				}, | ||||
| 				"weight-normal": { | ||||
| 					"type": "number", | ||||
|             "dns-weight": { | ||||
|             "type": "integer", | ||||
|             "default": 256 | ||||
| 				}, | ||||
| 				"weight-priority": { | ||||
| 					"type": "number", | ||||
| 					"default": 394 | ||||
| 				}, | ||||
| 				"weight-bulk": { | ||||
| 					"type": "number", | ||||
| 					"default": 128 | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| @@ -2473,8 +2180,8 @@ static json DefaultUCentralSchema = R"( | ||||
|             "facebook-wifi": { | ||||
|             "$ref": "#/$defs/service.facebook-wifi" | ||||
|             }, | ||||
| 				"airtime-fairness": { | ||||
| 					"$ref": "#/$defs/service.airtime-fairness" | ||||
|             "airtime-policies": { | ||||
|             "$ref": "#/$defs/service.airtime-policies" | ||||
|         } | ||||
|     } | ||||
|     }, | ||||
| @@ -2610,32 +2317,16 @@ static json DefaultUCentralSchema = R"( | ||||
| } | ||||
|     )"_json; | ||||
|  | ||||
|     class custom_error_handler : public nlohmann::json_schema::basic_error_handler | ||||
|     { | ||||
|         void error(const nlohmann::json_pointer<nlohmann::basic_json<>> &pointer, const json &instance, | ||||
|                    const std::string &message) override | ||||
|         { | ||||
|             nlohmann::json_schema::basic_error_handler::error(pointer, instance, message); | ||||
|             std::cout << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n"; | ||||
|         } | ||||
|     }; | ||||
|     class ConfigurationValidator *ConfigurationValidator::instance_ = nullptr; | ||||
|  | ||||
|     void ConfigurationValidator::Init() { | ||||
|         if(Initialized_) | ||||
|             return; | ||||
|  | ||||
|         std::string GitSchema; | ||||
| 		if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) { | ||||
| 			RootSchema_ = DefaultUCentralSchema; | ||||
| 			Logger().information("Using uCentral validation from built-in default."); | ||||
| 			Initialized_ = Working_ = true; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         try { | ||||
| 			auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile); | ||||
|             if(Utils::wgets(GitURI, GitSchema)) { | ||||
|                 RootSchema_ = json::parse(GitSchema); | ||||
|             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { | ||||
|                 auto schema = json::parse(GitSchema); | ||||
|                 Validator_->set_root_schema(schema); | ||||
|                 Logger().information("Using uCentral validation schema from GIT."); | ||||
|             } else { | ||||
|                 std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" }; | ||||
| @@ -2643,11 +2334,12 @@ static json DefaultUCentralSchema = R"( | ||||
|                 std::stringstream   schema_file; | ||||
|                 schema_file << input.rdbuf(); | ||||
|                 input.close(); | ||||
|                 RootSchema_ = json::parse(schema_file.str()); | ||||
|                 auto schema = json::parse(schema_file.str()); | ||||
|                 Validator_->set_root_schema(schema); | ||||
|                 Logger().information("Using uCentral validation schema from local file."); | ||||
|             } | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             RootSchema_ = DefaultUCentralSchema; | ||||
|             Validator_->set_root_schema(DefaultUCentralSchema); | ||||
|             Logger().information("Using uCentral validation from built-in default."); | ||||
|         } | ||||
|         Initialized_ = Working_ = true; | ||||
| @@ -2700,17 +2392,6 @@ static json DefaultUCentralSchema = R"( | ||||
|         return IsCIDRv4(value) || IsCIDRv6(value); | ||||
|     } | ||||
|  | ||||
|     static inline bool IsPortRangeIsValid(const std::string &r) { | ||||
|         const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM); | ||||
|  | ||||
|         for(const auto &port:ports) { | ||||
|             uint32_t port_num = std::stoul(port); | ||||
|             if(port_num==0 || port_num>65535) | ||||
|                 return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) | ||||
|     { | ||||
|         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; | ||||
| @@ -2733,7 +2414,7 @@ static json DefaultUCentralSchema = R"( | ||||
|         } else if(format == "uc-mac") { | ||||
|             if(std::regex_match(value,mac_regex)) | ||||
|                 return; | ||||
|             throw std::invalid_argument(value + " is not a valid MAC: should be something like 11:22:33:44:55:66"); | ||||
|             throw std::invalid_argument(value + " is not a valid MAC: should be something like 2e60:3500::/64."); | ||||
|         } else if(format == "uc-timeout") { | ||||
|             if(std::regex_match(value,uc_timeout_regex)) | ||||
|                 return; | ||||
| @@ -2761,20 +2442,16 @@ static json DefaultUCentralSchema = R"( | ||||
|             } catch (...) { | ||||
|             } | ||||
|             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); | ||||
|         } else if(format == "uc-portrange") { | ||||
|             try { | ||||
|                 if(IsPortRangeIsValid(value)) | ||||
|                     return; | ||||
|                 throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||
|             } catch (...) { | ||||
|             } | ||||
|             throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||
|         } else if(format == "ip") { | ||||
|             if (IsIP(value)) | ||||
|                 return; | ||||
|             throw std::invalid_argument(value + " is not a valid IP address."); | ||||
|         } else { | ||||
|             try { | ||||
|                 nlohmann::json_schema::default_string_format_check(format,value); | ||||
|             } catch (const std::logic_error &E) { | ||||
|                 std::string Error{"JSON Schema validation: "}; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -2782,31 +2459,18 @@ static json DefaultUCentralSchema = R"( | ||||
|         if(Working_) { | ||||
|             try { | ||||
|                 auto Doc = json::parse(C); | ||||
|                 custom_error_handler CE; | ||||
|                 json_validator  Validator(nullptr, my_format_checker); | ||||
|                 Validator.set_root_schema(RootSchema_); | ||||
|                 Validator.validate(Doc,CE); | ||||
|                 Validator_->validate(Doc); | ||||
|                 return true; | ||||
|             } catch (const std::invalid_argument &E) { | ||||
|                 std::cout << "1 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 Error = E.what(); | ||||
|                 return false; | ||||
|             } catch (const std::logic_error &E) { | ||||
|                 std::cout << "2 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 Error = E.what(); | ||||
|                 return false; | ||||
|             } catch(const std::exception &E) { | ||||
|                 Error = E.what(); | ||||
|                 std::cout << "3 Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 std::cout << "Validation failed, here is why: " << E.what() << "\n"; | ||||
|                 return false; | ||||
|             } catch(...) { | ||||
|                 std::cout << "4 Some kind of bullshit exception..." << std::endl; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) { | ||||
|     void ConfigurationValidator::reinitialize(Poco::Util::Application &self) { | ||||
|         Logger().information("Reinitializing."); | ||||
|         Working_ = Initialized_ = false; | ||||
|         Init(); | ||||
|   | ||||
| @@ -14,8 +14,9 @@ namespace OpenWifi { | ||||
|     class ConfigurationValidator : public  SubSystemServer { | ||||
|     public: | ||||
|  | ||||
|         static auto instance() { | ||||
|             static auto instance_ = new ConfigurationValidator; | ||||
|         static ConfigurationValidator *instance() { | ||||
|             if(instance_== nullptr) | ||||
|                 instance_ = new ConfigurationValidator; | ||||
|             return instance_; | ||||
|         } | ||||
|  | ||||
| @@ -26,17 +27,18 @@ namespace OpenWifi { | ||||
|         void reinitialize(Poco::Util::Application &self) override; | ||||
|  | ||||
|     private: | ||||
|         static  ConfigurationValidator * instance_; | ||||
|         bool            Initialized_=false; | ||||
|         bool            Working_=false; | ||||
|         void            Init(); | ||||
|         nlohmann::json  RootSchema_; | ||||
|         std::unique_ptr<json_validator>  Validator_=std::make_unique<json_validator>(nullptr, my_format_checker); | ||||
|  | ||||
|         ConfigurationValidator(): | ||||
|             SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); } | ||||
|     inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); } | ||||
|     inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ namespace OpenWifi::KafkaTopics { | ||||
| 	static const std::string SERVICE_EVENTS{"service_events"}; | ||||
| 	static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; | ||||
| 	static const std::string DEVICE_TELEMETRY{"device_telemetry"}; | ||||
|     static const std::string PROVISIONING_CHANGE{"provisioning_change"}; | ||||
|  | ||||
| 	namespace ServiceEvents { | ||||
| 		static const std::string EVENT_JOIN{"join"}; | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,299 +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 "Poco/JSON/Stringifier.h" | ||||
|  | ||||
| #include "Daemon.h" | ||||
| #ifdef	TIP_GATEWAY_SERVICE | ||||
| #include "DeviceRegistry.h" | ||||
| #include "CapabilitiesCache.h" | ||||
| #endif | ||||
|  | ||||
| #include "RESTAPI_GWobjects.h" | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| using OpenWifi::RESTAPI_utils::field_to_json; | ||||
| using OpenWifi::RESTAPI_utils::field_from_json; | ||||
| using OpenWifi::RESTAPI_utils::EmbedDocument; | ||||
|  | ||||
| namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); | ||||
| #endif | ||||
| 		field_to_json(Obj,"macAddress", MACAddress); | ||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		EmbedDocument("configuration", Obj, Configuration); | ||||
| 		field_to_json(Obj,"notes", Notes); | ||||
| 		field_to_json(Obj,"createdTimestamp", CreationTimestamp); | ||||
| 		field_to_json(Obj,"lastConfigurationChange", LastConfigurationChange); | ||||
| 		field_to_json(Obj,"lastConfigurationDownload", LastConfigurationDownload); | ||||
| 		field_to_json(Obj,"lastFWUpdate", LastFWUpdate); | ||||
| 		field_to_json(Obj,"owner", Owner); | ||||
| 		field_to_json(Obj,"location", Location); | ||||
| 		field_to_json(Obj,"venue", Venue); | ||||
| 		field_to_json(Obj,"firmware", Firmware); | ||||
| 		field_to_json(Obj,"compatible", Compatible); | ||||
| 		field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); | ||||
| 		field_to_json(Obj,"devicePassword", DevicePassword); | ||||
| 		field_to_json(Obj,"subscriber", subscriber); | ||||
| 		field_to_json(Obj,"entity", entity); | ||||
| 		field_to_json(Obj,"modified", modified); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
| 	} | ||||
|  | ||||
| 	void Device::to_json_with_status(Poco::JSON::Object &Obj) const { | ||||
| 		to_json(Obj); | ||||
|  | ||||
| #ifdef TIP_GATEWAY_SERVICE | ||||
| 		ConnectionState ConState; | ||||
|  | ||||
| 		if (DeviceRegistry()->GetState(SerialNumber, ConState)) { | ||||
| 			ConState.to_json(Obj); | ||||
| 		} else { | ||||
| 			field_to_json(Obj,"ipAddress", ""); | ||||
| 			field_to_json(Obj,"txBytes", (uint64_t) 0); | ||||
| 			field_to_json(Obj,"rxBytes", (uint64_t )0); | ||||
| 			field_to_json(Obj,"messageCount", (uint64_t )0); | ||||
| 			field_to_json(Obj,"connected", false); | ||||
| 			field_to_json(Obj,"lastContact", ""); | ||||
| 			field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); | ||||
| 			field_to_json(Obj,"associations_2G", (uint64_t) 0); | ||||
| 			field_to_json(Obj,"associations_5G", (uint64_t) 0); | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||
| 			field_from_json(Obj,"deviceType",DeviceType); | ||||
| 			field_from_json(Obj,"macAddress",MACAddress); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| 			field_from_json(Obj,"notes",Notes); | ||||
| 			field_from_json(Obj,"manufacturer",Manufacturer); | ||||
| 			field_from_json(Obj,"owner",Owner); | ||||
| 			field_from_json(Obj,"location",Location); | ||||
| 			field_from_json(Obj,"venue",Venue); | ||||
| 			field_from_json(Obj,"compatible",Compatible); | ||||
| 			field_from_json(Obj,"subscriber", subscriber); | ||||
| 			field_from_json(Obj,"entity", entity); | ||||
| 			field_from_json(Obj,"locale", locale); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void Device::Print() const { | ||||
| 		std::cout << "Device: " << SerialNumber << " DeviceType:" << DeviceType << " MACAddress:" << MACAddress << " Manufacturer:" | ||||
| 				  << Manufacturer << " " << Configuration << std::endl; | ||||
| 	} | ||||
|  | ||||
| 	void Statistics::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("data", Obj, Data); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 	} | ||||
|  | ||||
| 	void Capabilities::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("capabilities", Obj, Capabilities); | ||||
| 		field_to_json(Obj,"firstUpdate", FirstUpdate); | ||||
| 		field_to_json(Obj,"lastUpdate", LastUpdate); | ||||
| 	} | ||||
|  | ||||
| 	void DeviceLog::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("data", Obj, Data); | ||||
| 		field_to_json(Obj,"log", Log); | ||||
| 		field_to_json(Obj,"severity", Severity); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 		field_to_json(Obj,"logType", LogType); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 	} | ||||
|  | ||||
| 	void HealthCheck::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("values", Obj, Data); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"sanity", Sanity); | ||||
| 		field_to_json(Obj,"recorded", Recorded); | ||||
| 	} | ||||
|  | ||||
| 	void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("configuration", Obj, Configuration); | ||||
| 		field_to_json(Obj,"name", Name); | ||||
| 		field_to_json(Obj,"modelIds", Models); | ||||
| 		field_to_json(Obj,"description", Description); | ||||
| 		field_to_json(Obj,"created", Created); | ||||
| 		field_to_json(Obj,"lastModified", LastModified); | ||||
| 	} | ||||
|  | ||||
| 	void CommandDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		EmbedDocument("details", Obj, Details); | ||||
| 		EmbedDocument("results", Obj, Results); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| 		field_to_json(Obj,"command", Command); | ||||
| 		field_to_json(Obj,"errorText", ErrorText); | ||||
| 		field_to_json(Obj,"submittedBy", SubmittedBy); | ||||
| 		field_to_json(Obj,"status", Status); | ||||
| 		field_to_json(Obj,"submitted", Submitted); | ||||
| 		field_to_json(Obj,"executed", Executed); | ||||
| 		field_to_json(Obj,"completed", Completed); | ||||
| 		field_to_json(Obj,"when", RunAt); | ||||
| 		field_to_json(Obj,"errorCode", ErrorCode); | ||||
| 		field_to_json(Obj,"custom", Custom); | ||||
| 		field_to_json(Obj,"waitingForFile", WaitingForFile); | ||||
| 		field_to_json(Obj,"attachFile", AttachDate); | ||||
| 		field_to_json(Obj,"executionTime", executionTime); | ||||
| 	} | ||||
|  | ||||
| 	bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"name",Name); | ||||
| 			field_from_json(Obj,"configuration",Configuration); | ||||
| 			field_from_json(Obj,"modelIds",Models); | ||||
| 			field_from_json(Obj,"description",Description); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void BlackListedDevice::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", serialNumber); | ||||
| 		field_to_json(Obj,"author", author); | ||||
| 		field_to_json(Obj,"reason", reason); | ||||
| 		field_to_json(Obj,"created", created); | ||||
| 	} | ||||
|  | ||||
| 	bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"author",author); | ||||
| 			field_from_json(Obj,"reason",reason); | ||||
| 			field_from_json(Obj,"created",created); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"ipAddress", Address); | ||||
| 		field_to_json(Obj,"txBytes", TX); | ||||
| 		field_to_json(Obj,"rxBytes", RX); | ||||
| 		field_to_json(Obj,"messageCount", MessageCount); | ||||
| 		field_to_json(Obj,"UUID", UUID); | ||||
| 		field_to_json(Obj,"connected", Connected); | ||||
| 		field_to_json(Obj,"firmware", Firmware); | ||||
| 		field_to_json(Obj,"lastContact", LastContact); | ||||
| 		field_to_json(Obj,"associations_2G", Associations_2G); | ||||
| 		field_to_json(Obj,"associations_5G", Associations_5G); | ||||
| 		field_to_json(Obj,"webSocketClients", webSocketClients); | ||||
| 		field_to_json(Obj,"websocketPackets", websocketPackets); | ||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); | ||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | ||||
| 		field_to_json(Obj,"locale", locale); | ||||
|  | ||||
| 		switch(VerifiedCertificate) { | ||||
| 			case NO_CERTIFICATE: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break; | ||||
| 			case VALID_CERTIFICATE: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "VALID_CERTIFICATE"); break; | ||||
| 			case MISMATCH_SERIAL: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "MISMATCH_SERIAL"); break; | ||||
| 			case VERIFIED: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "VERIFIED"); break; | ||||
| 			default: | ||||
| 				field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||
| 		field_to_json(Obj,"server", Server); | ||||
| 		field_to_json(Obj,"port", Port); | ||||
| 		field_to_json(Obj,"token",Token); | ||||
| 		field_to_json(Obj,"timeout", TimeOut); | ||||
| 		field_to_json(Obj,"connectionId",ConnectionId); | ||||
| 		field_to_json(Obj,"commandUUID",CommandUUID); | ||||
| 		field_to_json(Obj,"started", Started); | ||||
| 		field_to_json(Obj,"viewport",ViewPort); | ||||
| 		field_to_json(Obj,"password",DevicePassword); | ||||
| 	} | ||||
|  | ||||
| 	void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"commands",commands); | ||||
| 		field_to_json(Obj,"upTimes",upTimes); | ||||
| 		field_to_json(Obj,"memoryUsed",memoryUsed); | ||||
| 		field_to_json(Obj,"load1",load1); | ||||
| 		field_to_json(Obj,"load5",load5); | ||||
| 		field_to_json(Obj,"load15",load15); | ||||
| 		field_to_json(Obj,"vendors",vendors); | ||||
| 		field_to_json(Obj,"status",status); | ||||
| 		field_to_json(Obj,"deviceType",deviceType); | ||||
| 		field_to_json(Obj,"healths",healths); | ||||
| 		field_to_json(Obj,"certificates",certificates); | ||||
| 		field_to_json(Obj,"lastContact",lastContact); | ||||
| 		field_to_json(Obj,"associations",associations); | ||||
| 		field_to_json(Obj,"snapshot",snapshot); | ||||
| 		field_to_json(Obj,"numberOfDevices",numberOfDevices); | ||||
| 	} | ||||
|  | ||||
| 	void Dashboard::reset()  { | ||||
| 		commands.clear(); | ||||
| 		upTimes.clear(); | ||||
| 		memoryUsed.clear(); | ||||
| 		load1.clear(); | ||||
| 		load5.clear(); | ||||
| 		load15.clear(); | ||||
| 		vendors.clear(); | ||||
| 		status.clear(); | ||||
| 		deviceType.clear(); | ||||
| 		healths.clear(); | ||||
| 		certificates.clear(); | ||||
| 		lastContact.clear(); | ||||
| 		associations.clear(); | ||||
| 		numberOfDevices = 0 ; | ||||
| 		snapshot = OpenWifi::Now(); | ||||
| 	} | ||||
|  | ||||
| 	void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ | ||||
| 		field_to_json(Obj,"deviceType", deviceType); | ||||
| 		field_to_json(Obj,"capabilities", capabilities); | ||||
| 	}; | ||||
|  | ||||
| 	void ScriptRequest::to_json(Poco::JSON::Object &Obj) const { | ||||
| 		field_to_json(Obj,"serialNumber",serialNumber); | ||||
| 		field_to_json(Obj,"timeout",timeout); | ||||
| 		field_to_json(Obj,"type",type); | ||||
| 		field_to_json(Obj,"script",script); | ||||
| 		field_to_json(Obj,"scriptId",scriptId); | ||||
| 		field_to_json(Obj,"when",when); | ||||
| 	} | ||||
|  | ||||
| 	bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		try { | ||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | ||||
| 			field_from_json(Obj,"timeout",timeout); | ||||
| 			field_from_json(Obj,"type",type); | ||||
| 			field_from_json(Obj,"script",script); | ||||
| 			field_from_json(Obj,"scriptId",scriptId); | ||||
| 			field_from_json(Obj,"when",when); | ||||
| 			return true; | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -1,213 +0,0 @@ | ||||
| // | ||||
| //	License type: BSD 3-Clause License | ||||
| //	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
| // | ||||
| //	Created by Stephane Bourque on 2021-03-04. | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Poco/JSON/Object.h" | ||||
| #include "RESTAPI_SecurityObjects.h" | ||||
|  | ||||
| namespace OpenWifi::GWObjects { | ||||
|  | ||||
| 	enum CertificateValidation { | ||||
| 		NO_CERTIFICATE, | ||||
| 		VALID_CERTIFICATE, | ||||
| 		MISMATCH_SERIAL, | ||||
| 		VERIFIED | ||||
| 	}; | ||||
|  | ||||
| 	struct ConnectionState { | ||||
| 		uint64_t MessageCount = 0 ; | ||||
| 		std::string Address; | ||||
| 		uint64_t UUID = 0 ; | ||||
| 		uint64_t PendingUUID = 0 ; | ||||
| 		uint64_t TX = 0, RX = 0; | ||||
| 		uint64_t Associations_2G=0; | ||||
| 		uint64_t Associations_5G=0; | ||||
| 		bool Connected = false; | ||||
| 		uint64_t LastContact=0; | ||||
| 		std::string Firmware; | ||||
| 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | ||||
| 		std::string Compatible; | ||||
| 		uint64_t 	kafkaClients=0; | ||||
| 		uint64_t 	webSocketClients=0; | ||||
| 		uint64_t 	kafkaPackets=0; | ||||
| 		uint64_t 	websocketPackets=0; | ||||
| 		std::string locale; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Device { | ||||
| 		std::string SerialNumber; | ||||
| 		std::string DeviceType; | ||||
| 		std::string MACAddress; | ||||
| 		std::string Manufacturer; | ||||
| 		std::string Configuration; | ||||
| 		SecurityObjects::NoteInfoVec 	Notes; | ||||
| 		std::string Owner; | ||||
| 		std::string Location; | ||||
| 		std::string Firmware; | ||||
| 		std::string Compatible; | ||||
| 		std::string FWUpdatePolicy; | ||||
| 		uint64_t UUID = 0 ; | ||||
| 		uint64_t CreationTimestamp = 0 ; | ||||
| 		uint64_t LastConfigurationChange = 0 ; | ||||
| 		uint64_t LastConfigurationDownload = 0 ; | ||||
| 		uint64_t LastFWUpdate = 0 ; | ||||
| 		std::string Venue; | ||||
| 		std::string DevicePassword; | ||||
| 		std::string subscriber; | ||||
| 		std::string entity; | ||||
| 		uint64_t 	modified=0; | ||||
| 		std::string locale; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 		void Print() const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Statistics { | ||||
| 		std::string SerialNumber; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Recorded = 0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct HealthCheck { | ||||
| 		std::string SerialNumber; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Recorded = 0 ; | ||||
| 		uint64_t 	Sanity = 0 ; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Capabilities { | ||||
| 		std::string Capabilities; | ||||
| 		uint64_t 	FirstUpdate = 0 ; | ||||
| 		uint64_t 	LastUpdate = 0 ; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct DeviceLog { | ||||
| 		enum Level { | ||||
| 			LOG_EMERG = 0,	 /* system is unusable */ | ||||
| 			LOG_ALERT = 1,	 /* action must be taken immediately */ | ||||
| 			LOG_CRIT = 2,	 /* critical conditions */ | ||||
| 			LOG_ERR = 3,	 /* error conditions */ | ||||
| 			LOG_WARNING = 4, /* warning conditions */ | ||||
| 			LOG_NOTICE = 5,	 /* normal but significant condition */ | ||||
| 			LOG_INFO = 6,	 /* informational */ | ||||
| 			LOG_DEBUG = 7	 /* debug-level messages */ | ||||
| 		}; | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Log; | ||||
| 		std::string Data; | ||||
| 		uint64_t 	Severity = 0 ; | ||||
| 		uint64_t 	Recorded = 0 ; | ||||
| 		uint64_t 	LogType = 0 ; | ||||
| 		uint64_t 	UUID = 0 ; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct DefaultConfiguration { | ||||
| 		std::string Name; | ||||
| 		std::string Configuration; | ||||
| 		Types::StringVec Models; | ||||
| 		std::string Description; | ||||
| 		uint64_t 	Created; | ||||
| 		uint64_t 	LastModified; | ||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool 		from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct CommandDetails { | ||||
| 		std::string UUID; | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Command; | ||||
| 		std::string Status; | ||||
| 		std::string SubmittedBy; | ||||
| 		std::string Results; | ||||
| 		std::string Details; | ||||
| 		std::string ErrorText; | ||||
| 		uint64_t Submitted = time(nullptr); | ||||
| 		uint64_t Executed = 0; | ||||
| 		uint64_t Completed = 0 ; | ||||
| 		uint64_t RunAt = 0 ; | ||||
| 		uint64_t ErrorCode = 0 ; | ||||
| 		uint64_t Custom = 0 ; | ||||
| 		uint64_t WaitingForFile = 0 ; | ||||
| 		uint64_t AttachDate = 0 ; | ||||
| 		uint64_t AttachSize = 0 ; | ||||
| 		std::string AttachType; | ||||
| 		double 		executionTime = 0.0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct BlackListedDevice { | ||||
| 		std::string serialNumber; | ||||
| 		std::string reason; | ||||
| 		std::string author; | ||||
| 		uint64_t created; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
|  | ||||
| 	struct RttySessionDetails { | ||||
| 		std::string SerialNumber; | ||||
| 		std::string Server; | ||||
| 		uint64_t 	Port = 0 ; | ||||
| 		std::string Token; | ||||
| 		uint64_t 	TimeOut = 0 ; | ||||
| 		std::string ConnectionId; | ||||
| 		uint64_t 	Started = 0 ; | ||||
| 		std::string CommandUUID; | ||||
| 		uint64_t 	ViewPort = 0 ; | ||||
| 		std::string DevicePassword; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct Dashboard { | ||||
| 		uint64_t 		  snapshot = 0 ; | ||||
| 		uint64_t 		  numberOfDevices = 0 ; | ||||
| 		Types::CountedMap commands; | ||||
| 		Types::CountedMap upTimes; | ||||
| 		Types::CountedMap memoryUsed; | ||||
| 		Types::CountedMap load1; | ||||
| 		Types::CountedMap load5; | ||||
| 		Types::CountedMap load15; | ||||
| 		Types::CountedMap vendors; | ||||
| 		Types::CountedMap status; | ||||
| 		Types::CountedMap deviceType; | ||||
| 		Types::CountedMap healths; | ||||
| 		Types::CountedMap certificates; | ||||
| 		Types::CountedMap lastContact; | ||||
| 		Types::CountedMap associations; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		void reset(); | ||||
| 	}; | ||||
|  | ||||
| 	struct CapabilitiesModel { | ||||
| 		std::string deviceType; | ||||
| 		std::string capabilities; | ||||
|  | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 	}; | ||||
|  | ||||
| 	struct ScriptRequest { | ||||
| 		uint64_t 	timeout=30; | ||||
| 		std::string serialNumber; | ||||
| 		std::string type; | ||||
| 		std::string script; | ||||
| 		std::string scriptId; | ||||
| 		uint64_t 	when=0; | ||||
| 		void to_json(Poco::JSON::Object &Obj) const; | ||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||
| 	}; | ||||
| } | ||||
							
								
								
									
										68
									
								
								src/framework/RESTAPI_errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/framework/RESTAPI_errors.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2021-09-12. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace OpenWifi::RESTAPI::Errors { | ||||
|     static const std::string MissingUUID{"Missing UUID."}; | ||||
|     static const std::string MissingSerialNumber{"Missing Serial Number."}; | ||||
|     static const std::string InternalError{"Internal error. Please try later."}; | ||||
|     static const std::string InvalidJSONDocument{"Invalid JSON document."}; | ||||
|     static const std::string UnsupportedHTTPMethod{"Unsupported HTTP Method"}; | ||||
|     static const std::string StillInUse{"Element still in use."}; | ||||
|     static const std::string CouldNotBeDeleted{"Element could not be deleted."}; | ||||
|     static const std::string NameMustBeSet{"The name property must be set."}; | ||||
|     static const std::string ConfigBlockInvalid{"Configuration block type invalid."}; | ||||
|     static const std::string UnknownId{"Unknown UUID."}; | ||||
|     static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."}; | ||||
|     static const std::string RecordNotCreated{"Record could not be created."}; | ||||
|     static const std::string RecordNotUpdated{"Record could not be updated."}; | ||||
|     static const std::string UnknownManagementPolicyUUID{"Unknown management policy UUID."}; | ||||
|     static const std::string CannotDeleteRoot{"Root Entity cannot be removed, only modified."}; | ||||
|     static const std::string MustCreateRootFirst{"Root entity must be created first."}; | ||||
|     static const std::string ParentUUIDMustExist{"Parent UUID must exist."}; | ||||
|     static const std::string ConfigurationMustExist{"Configuration must exist."}; | ||||
|     static const std::string MissingOrInvalidParameters{"Invalid or missing parameters."}; | ||||
|     static const std::string UnknownSerialNumber{"Unknown Serial Number."}; | ||||
|     static const std::string InvalidSerialNumber{"Invalid Serial Number."}; | ||||
|     static const std::string SerialNumberExists{"Serial Number already exists."}; | ||||
|     static const std::string ValidNonRootUUID{"Must be a non-root, and valid UUID."}; | ||||
|     static const std::string VenueMustExist{"Venue does not exist."}; | ||||
|     static const std::string NotBoth{"You cannot specify both Entity and Venue"}; | ||||
|     static const std::string EntityMustExist{"Entity must exist."}; | ||||
|     static const std::string ParentOrEntityMustBeSet{"Parent or Entity must be set."}; | ||||
|     static const std::string ContactMustExist{"Contact must exist."}; | ||||
|     static const std::string LocationMustExist{"Location must exist."}; | ||||
|     static const std::string OnlyWSSupported{"This endpoint only supports WebSocket."}; | ||||
|     static const std::string SerialNumberMismatch{"Serial Number mismatch."}; | ||||
|     static const std::string InvalidCommand{"Invalid command."}; | ||||
|     static const std::string NoRecordsDeleted{"No records deleted."}; | ||||
|     static const std::string DeviceNotConnected{"Device is not currently connected."}; | ||||
|     static const std::string CannotCreateWS{"Telemetry system could not create WS endpoint. Please try again."}; | ||||
|     static const std::string BothDeviceTypeRevision{"Both deviceType and revision must be set."}; | ||||
|     static const std::string IdOrSerialEmpty{"SerialNumber and Id must not be empty."}; | ||||
|     static const std::string MissingUserID{"Missing user ID."}; | ||||
|     static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; | ||||
|     static const std::string InvalidUserRole{"Invalid userRole."}; | ||||
|     static const std::string InvalidEmailAddress{"Invalid email address."}; | ||||
|     static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; | ||||
|     static const std::string InvalidIPRanges{"Invalid IP range specifications."}; | ||||
|     static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; | ||||
|     static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; | ||||
|     static const std::string BadMFAMethod{"MFA only supports sms or email."}; | ||||
|     static const std::string InvalidCredentials{"Invalid credentials (username/password)."}; | ||||
|     static const std::string InvalidPassword{"Password does not conform to basic password rules."}; | ||||
|     static const std::string UserPendingVerification{"User access denied pending email verification."}; | ||||
|     static const std::string PasswordMustBeChanged{"Password must be changed."}; | ||||
|     static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; | ||||
|     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; | ||||
|     static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; | ||||
|     static const std::string ExpiredToken{"Token has expired, user must login."}; | ||||
|     static const std::string SubscriberMustExist{"Subscriber must exist."}; | ||||
|     static const std::string AuthenticatorVerificationIncomplete{"Authenticator validation is not complete."}; | ||||
|     static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."}; | ||||
|     static const std::string SMSCouldNotValidate{"Code and number could not be validated"}; | ||||
|     static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"}; | ||||
| } | ||||
|  | ||||
							
								
								
									
										139
									
								
								src/framework/RESTAPI_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/framework/RESTAPI_protocol.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| // | ||||
| //	License type: BSD 3-Clause License | ||||
| //	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
| // | ||||
| //	Created by Stephane Bourque on 2021-03-04. | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace OpenWifi::RESTAPI::Protocol { | ||||
| 	static const char * CAPABILITIES = "capabilities"; | ||||
| 	static const char * LOGS = "logs"; | ||||
| 	static const char * HEALTHCHECKS = "healthchecks"; | ||||
| 	static const char * STATISTICS = "statistics"; | ||||
| 	static const char * STATUS = "status"; | ||||
| 	static const char * SERIALNUMBER = "serialNumber"; | ||||
| 	static const char * PERFORM = "perform"; | ||||
| 	static const char * CONFIGURE = "configure"; | ||||
| 	static const char * UPGRADE = "upgrade"; | ||||
| 	static const char * REBOOT = "reboot"; | ||||
| 	static const char * FACTORY = "factory"; | ||||
| 	static const char * LEDS = "leds"; | ||||
| 	static const char * TRACE = "trace"; | ||||
| 	static const char * REQUEST = "request"; | ||||
| 	static const char * WIFISCAN = "wifiscan"; | ||||
| 	static const char * EVENTQUEUE = "eventqueue"; | ||||
| 	static const char * RTTY = "rtty"; | ||||
| 	static const char * COMMAND = "command"; | ||||
| 	static const char * STARTDATE = "startDate"; | ||||
| 	static const char * ENDDATE = "endDate"; | ||||
| 	static const char * OFFSET = "offset"; | ||||
| 	static const char * LIMIT = "limit"; | ||||
| 	static const char * LIFETIME = "lifetime"; | ||||
| 	static const char * UUID = "UUID"; | ||||
| 	static const char * DATA = "data"; | ||||
| 	static const char * CONFIGURATION = "configuration"; | ||||
| 	static const char * WHEN = "when"; | ||||
| 	static const char * URI = "uri"; | ||||
| 	static const char * LOGTYPE = "logType"; | ||||
| 	static const char * VALUES = "values"; | ||||
| 	static const char * TYPES = "types"; | ||||
| 	static const char * PAYLOAD = "payload"; | ||||
| 	static const char * KEEPREDIRECTOR = "keepRedirector"; | ||||
| 	static const char * NETWORK = "network"; | ||||
| 	static const char * INTERFACE = "interface"; | ||||
| 	static const char * BANDS = "bands"; | ||||
| 	static const char * CHANNELS = "channels"; | ||||
| 	static const char * VERBOSE = "verbose"; | ||||
| 	static const char * MESSAGE = "message"; | ||||
| 	static const char * STATE = "state"; | ||||
| 	static const char * HEALTHCHECK = "healthcheck"; | ||||
| 	static const char * PCAP_FILE_TYPE = "pcap"; | ||||
| 	static const char * DURATION = "duration"; | ||||
| 	static const char * NUMBEROFPACKETS = "numberOfPackets"; | ||||
| 	static const char * FILTER = "filter"; | ||||
| 	static const char * SELECT = "select"; | ||||
| 	static const char * SERIALONLY = "serialOnly"; | ||||
| 	static const char * COUNTONLY = "countOnly"; | ||||
| 	static const char * DEVICEWITHSTATUS = "deviceWithStatus"; | ||||
| 	static const char * DEVICESWITHSTATUS = "devicesWithStatus"; | ||||
| 	static const char * DEVICES = "devices"; | ||||
| 	static const char * COUNT = "count"; | ||||
| 	static const char * SERIALNUMBERS = "serialNumbers"; | ||||
| 	static const char * CONFIGURATIONS = "configurations"; | ||||
| 	static const char * NAME = "name"; | ||||
| 	static const char * COMMANDS = "commands"; | ||||
| 	static const char * COMMANDUUID = "commandUUID"; | ||||
| 	static const char * FIRMWARES = "firmwares"; | ||||
| 	static const char * TOPIC = "topic"; | ||||
| 	static const char * HOST = "host"; | ||||
| 	static const char * OS = "os"; | ||||
| 	static const char * HOSTNAME = "hostname"; | ||||
| 	static const char * PROCESSORS = "processors"; | ||||
| 	static const char * REASON = "reason"; | ||||
| 	static const char * RELOAD = "reload"; | ||||
| 	static const char * SUBSYSTEMS = "subsystems"; | ||||
| 	static const char * FILEUUID = "uuid"; | ||||
| 	static const char * USERID = "userId"; | ||||
| 	static const char * PASSWORD = "password"; | ||||
| 	static const char * TOKEN = "token"; | ||||
| 	static const char * SETLOGLEVEL = "setloglevel"; | ||||
| 	static const char * GETLOGLEVELS = "getloglevels"; | ||||
| 	static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; | ||||
| 	static const char * GETLOGLEVELNAMES = "getloglevelnames"; | ||||
| 	static const char * STATS = "stats"; | ||||
| 	static const char * PING = "ping"; | ||||
| 	static const char * PARAMETERS = "parameters"; | ||||
| 	static const char * VALUE = "value"; | ||||
| 	static const char * LASTONLY = "lastOnly"; | ||||
| 	static const char * NEWEST = "newest"; | ||||
| 	static const char * ACTIVESCAN = "activeScan"; | ||||
| 	static const char * OVERRIDEDFS = "override_dfs"; | ||||
| 	static const char * LIST = "list"; | ||||
| 	static const char * TAG = "tag"; | ||||
| 	static const char * TAGLIST = "tagList"; | ||||
|     static const char * DESCRIPTION = "description"; | ||||
|     static const char * NOTES = "notes"; | ||||
|     static const char * DEVICETYPE = "deviceType"; | ||||
|     static const char * REVISION = "revision"; | ||||
|     static const char * AGES = "ages"; | ||||
|     static const char * REVISIONS = "revisions"; | ||||
|     static const char * DEVICETYPES = "deviceTypes"; | ||||
|     static const char * LATESTONLY = "latestOnly"; | ||||
|     static const char * IDONLY = "idOnly"; | ||||
|     static const char * REVISIONSET = "revisionSet"; | ||||
|     static const char * DEVICESET = "deviceSet"; | ||||
|     static const char * HISTORY = "history"; | ||||
|     static const char * ID = "id"; | ||||
|     static const char * VERSION = "version"; | ||||
|     static const char * TIMES = "times"; | ||||
|     static const char * UPTIME = "uptime"; | ||||
|     static const char * START = "start"; | ||||
|  | ||||
|     static const char * NEWPASSWORD = "newPassword"; | ||||
|     static const char * USERS = "users"; | ||||
|     static const char * WITHEXTENDEDINFO = "withExtendedInfo"; | ||||
|  | ||||
|     static const char * ERRORTEXT = "errorText"; | ||||
|     static const char * ERRORCODE = "errorCode"; | ||||
|     static const char * AVATARID = "avatarId"; | ||||
|     static const char * UNNAMED = "(unnamed)"; | ||||
|     static const char * UNSPECIFIED = "(unspecified)"; | ||||
|     static const char * CONTENTDISPOSITION = "Content-Disposition"; | ||||
|     static const char * CONTENTTYPE = "Content-Type"; | ||||
|  | ||||
|     static const char * REQUIREMENTS = "requirements"; | ||||
|     static const char * PASSWORDPATTERN = "passwordPattern"; | ||||
|     static const char * ACCESSPOLICY = "accessPolicy"; | ||||
|     static const char * PASSWORDPOLICY = "passwordPolicy"; | ||||
|     static const char * FORGOTPASSWORD = "forgotPassword"; | ||||
|     static const char * RESENDMFACODE = "resendMFACode"; | ||||
|     static const char * COMPLETEMFACHALLENGE = "completeMFAChallenge"; | ||||
|     static const char * ME = "me"; | ||||
|     static const char * TELEMETRY = "telemetry"; | ||||
|     static const char * INTERVAL = "interval"; | ||||
|     static const char * UI = "UI"; | ||||
|  | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user