mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 10:47:48 +00:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 24b022fa60 | ||
|   | 88922786ff | ||
|   | 4510cd034f | ||
|   | af5774ce36 | ||
|   | 2573b8cd4f | ||
|   | 9c5b18a536 | ||
|   | 768c428a67 | ||
|   | 389ceb8b7d | ||
|   | 157f18c117 | ||
|   | 2538f9c768 | ||
|   | 85d998ad76 | ||
|   | a407f2e38d | ||
|   | d0d2be0870 | ||
|   | 78cba562e6 | ||
|   | 350df38c3f | 
							
								
								
									
										73
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -25,46 +25,45 @@ jobs: | |||||||
|       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io |       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|       DOCKER_REGISTRY_USERNAME: ucentral |       DOCKER_REGISTRY_USERNAME: ucentral | ||||||
|     steps: |     steps: | ||||||
|     - name: Checkout actions repo |     - uses: actions/checkout@v2 | ||||||
|       uses: actions/checkout@v2 |  | ||||||
|       with: |  | ||||||
|         repository: Telecominfraproject/.github |  | ||||||
|         path: github |  | ||||||
|  |  | ||||||
|     - name: Build and push Docker image |     - name: Build Docker image | ||||||
|       uses: ./github/composite-actions/docker-image-build |       run: docker build -t wlan-cloud-owsec:${{ github.sha }} . | ||||||
|       with: |  | ||||||
|         image_name: owsec |  | ||||||
|         registry: tip-tip-wlan-cloud-ucentral.jfrog.io |  | ||||||
|         registry_user: ucentral |  | ||||||
|         registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} |  | ||||||
|  |  | ||||||
|   trigger-testing: |     - name: Tag Docker image | ||||||
|     if: startsWith(github.ref, 'refs/pull/') |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     needs: docker |  | ||||||
|     steps: |  | ||||||
|     - name: Get base branch name and set as output |  | ||||||
|       id: get_base_branch |  | ||||||
|       run: | |       run: | | ||||||
|         echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/}) |         TAGS="${{ github.sha }}" | ||||||
|         echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g') |  | ||||||
|  |  | ||||||
|     - name: Checkout actions repo |         if [[ ${GITHUB_REF} == "refs/heads/"* ]] | ||||||
|       uses: actions/checkout@v2 |         then | ||||||
|       with: |           CURRENT_TAG=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-') | ||||||
|         repository: Telecominfraproject/.github |           TAGS="$TAGS $CURRENT_TAG" | ||||||
|         path: github |         else | ||||||
|  |           if [[ ${GITHUB_REF} == "refs/tags/"* ]] | ||||||
|  |           then | ||||||
|  |             CURRENT_TAG=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-') | ||||||
|  |             TAGS="$TAGS $CURRENT_TAG" | ||||||
|  |           else # PR build | ||||||
|  |             CURRENT_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||||
|  |             TAGS="$TAGS $CURRENT_TAG" | ||||||
|  |           fi | ||||||
|  |         fi | ||||||
|  |  | ||||||
|     - name: Trigger testing of OpenWifi Docker Compose deployment and wait for result |         echo "Result tags: $TAGS" | ||||||
|       uses: ./github/composite-actions/trigger-workflow-and-wait |  | ||||||
|       env: |         for tag in $TAGS; do | ||||||
|         BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }} |           docker tag wlan-cloud-owsec:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owsec:$tag | ||||||
|         OWGW_BASE_BRANCH: ${{ steps.get_base_branch.outputs.owgw_branch }} |         done | ||||||
|  |  | ||||||
|  |     - name: Log into Docker registry | ||||||
|  |       if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main' | ||||||
|  |       uses: docker/login-action@v1 | ||||||
|       with: |       with: | ||||||
|         owner: Telecominfraproject |         registry: ${{ env.DOCKER_REGISTRY_URL }} | ||||||
|         repo: wlan-testing |         username: ${{ env.DOCKER_REGISTRY_USERNAME }} | ||||||
|         workflow: ow_docker-compose.yml |         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} | ||||||
|         token: ${{ secrets.WLAN_TESTING_PAT }} |  | ||||||
|         ref: master |     - name: Push Docker images | ||||||
|         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"}' |       if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main' | ||||||
|  |       run: | | ||||||
|  |         docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owsec | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {} | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | |||||||
| name: Ensure Jira issue is linked |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   pull_request: |  | ||||||
|     types: [opened, edited, reopened, synchronize] |  | ||||||
|     branches: |  | ||||||
|       - 'release/*' |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   check_for_issue_key: |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     steps: |  | ||||||
|       - name: Checkout actions repo |  | ||||||
|         uses: actions/checkout@v2 |  | ||||||
|         with: |  | ||||||
|           repository: Telecominfraproject/.github |  | ||||||
|           path: github |  | ||||||
|  |  | ||||||
|       - name: Run JIRA check |  | ||||||
|         uses: ./github/composite-actions/enforce-jira-issue-key |  | ||||||
|         with: |  | ||||||
|           jira_base_url: ${{ secrets.TIP_JIRA_URL }} |  | ||||||
|           jira_user_email: ${{ secrets.TIP_JIRA_USER_EMAIL }} |  | ||||||
|           jira_api_token: ${{ secrets.TIP_JIRA_API_TOKEN }} |  | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| cmake_minimum_required(VERSION 3.13) | cmake_minimum_required(VERSION 3.13) | ||||||
| project(owsec VERSION 2.5.0) | project(owsec VERSION 2.4.0) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 17) | set(CMAKE_CXX_STANDARD 17) | ||||||
|  |  | ||||||
| @@ -20,14 +20,14 @@ endif() | |||||||
|  |  | ||||||
| # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 | # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 | ||||||
| if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) | ||||||
|     file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM) |     file(READ build BUILD_NUM) | ||||||
|     if(BUILD_INCREMENT) |     if(BUILD_INCREMENT) | ||||||
|         MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") |         MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") | ||||||
|         file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) |         file(WRITE build ${BUILD_NUM}) | ||||||
|     endif() |     endif() | ||||||
| else() | else() | ||||||
|     set(BUILD_NUM 1) |     set(BUILD_NUM 1) | ||||||
|     file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) |     file(WRITE build ${BUILD_NUM}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| find_package(Git QUIET) | find_package(Git QUIET) | ||||||
| @@ -41,11 +41,9 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") | |||||||
|     endif() |     endif() | ||||||
|     string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") |     string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT) | add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT) | ||||||
|  |  | ||||||
| set(BUILD_SHARED_LIBS 1) | set(BUILD_SHARED_LIBS 1) | ||||||
|  |  | ||||||
| add_definitions(-DTIP_SECURITY_SERVICE="1") | add_definitions(-DTIP_SECURITY_SERVICE="1") | ||||||
|  |  | ||||||
| set(Boost_USE_STATIC_LIBS OFF) | set(Boost_USE_STATIC_LIBS OFF) | ||||||
| @@ -71,40 +69,30 @@ add_executable( owsec | |||||||
|         src/framework/CountryCodes.h |         src/framework/CountryCodes.h | ||||||
|         src/framework/KafkaTopics.h |         src/framework/KafkaTopics.h | ||||||
|         src/framework/MicroService.h |         src/framework/MicroService.h | ||||||
|  |         src/framework/OpenWifiTypes.h | ||||||
|         src/framework/orm.h |         src/framework/orm.h | ||||||
|         src/framework/RESTAPI_errors.h |         src/framework/RESTAPI_errors.h | ||||||
|         src/framework/RESTAPI_protocol.h |         src/framework/RESTAPI_protocol.h | ||||||
|         src/framework/StorageClass.h |         src/framework/StorageClass.h | ||||||
|         src/framework/uCentral_Protocol.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 |  | ||||||
|         src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h |  | ||||||
|         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp |         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp | ||||||
|         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h |         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h | ||||||
|         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp |         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp | ||||||
|         src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp |         src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp | ||||||
|         src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp |         src/RESTAPI/RESTAPI_oauth2Handler.h src/RESTAPI/RESTAPI_oauth2Handler.cpp | ||||||
|         src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h |         src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h | ||||||
|         src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h |         src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h | ||||||
|         src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h |         src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h | ||||||
|         src/RESTAPI/RESTAPI_validate_token_handler.cpp src/RESTAPI/RESTAPI_validate_token_handler.h |         src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h | ||||||
|         src/RESTAPI/RESTAPI_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h |         src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h | ||||||
|         src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h |         src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h | ||||||
|         src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h |         src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.h | ||||||
|         src/RESTAPI/RESTAPI_subavatar_handler.cpp src/RESTAPI/RESTAPI_subavatar_handler.h |  | ||||||
|         src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h |         src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h | ||||||
|         src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h |         src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h | ||||||
|         src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp |         src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h | ||||||
|         src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp |         src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp | ||||||
|         src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp |         src/APIServers.cpp | ||||||
|         src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp src/RESTAPI/RESTAPI_validate_sub_token_handler.h |  | ||||||
|         src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h |  | ||||||
|         src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h |  | ||||||
|         src/RESTAPI/RESTAPI_subpreferences.cpp src/RESTAPI/RESTAPI_subpreferences.h |  | ||||||
|         src/RESTAPI/RESTAPI_routers.cpp |  | ||||||
|         src/Daemon.h src/Daemon.cpp |         src/Daemon.h src/Daemon.cpp | ||||||
|         src/SpecialUserHelpers.h |  | ||||||
|         src/AuthService.h src/AuthService.cpp |         src/AuthService.h src/AuthService.cpp | ||||||
|         src/StorageService.cpp src/StorageService.h |         src/StorageService.cpp src/StorageService.h | ||||||
|         src/SMTPMailerService.cpp src/SMTPMailerService.h |         src/SMTPMailerService.cpp src/SMTPMailerService.h | ||||||
| @@ -113,16 +101,10 @@ add_executable( owsec | |||||||
|         src/SMS_provider_aws.cpp src/SMS_provider_aws.h |         src/SMS_provider_aws.cpp src/SMS_provider_aws.h | ||||||
|         src/SMS_provider.cpp src/SMS_provider.h |         src/SMS_provider.cpp src/SMS_provider.h | ||||||
|         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h |         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h | ||||||
|  |         src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h | ||||||
|  |         src/storage/storage_tokens.h | ||||||
|         src/ActionLinkManager.cpp src/ActionLinkManager.h |         src/ActionLinkManager.cpp src/ActionLinkManager.h | ||||||
|         src/ACLProcessor.h |         src/ACLProcessor.h) | ||||||
|         src/framework/OpenWifiTypes.h |  | ||||||
|         src/storage/orm_users.cpp src/storage/orm_users.h |  | ||||||
|         src/storage/orm_tokens.cpp src/storage/orm_tokens.h |  | ||||||
|         src/storage/orm_preferences.cpp src/storage/orm_preferences.h |  | ||||||
|         src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h |  | ||||||
|         src/storage/orm_avatar.cpp src/storage/orm_avatar.h |  | ||||||
|         src/SpecialUserHelpers.h |  | ||||||
|         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h) |  | ||||||
|  |  | ||||||
| if(NOT SMALL_BUILD) | if(NOT SMALL_BUILD) | ||||||
|     target_link_libraries(owsec PUBLIC |     target_link_libraries(owsec PUBLIC | ||||||
|   | |||||||
							
								
								
									
										115
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,51 +1,18 @@ | |||||||
| FROM alpine:3.15 AS build-base | FROM alpine AS builder | ||||||
|  |  | ||||||
| RUN apk add --update --no-cache \ | RUN apk add --update --no-cache \ | ||||||
|     make cmake g++ git \ |     openssl openssh \ | ||||||
|     unixodbc-dev postgresql-dev mariadb-dev \ |     ncurses-libs \ | ||||||
|     librdkafka-dev boost-dev openssl-dev \ |     bash util-linux coreutils curl libcurl \ | ||||||
|     zlib-dev nlohmann-json \ |     make cmake gcc g++ libstdc++ libgcc git zlib-dev \ | ||||||
|     curl-dev |     openssl-dev boost-dev curl-dev unixodbc-dev postgresql-dev mariadb-dev \ | ||||||
|  |     apache2-utils yaml-dev apr-util-dev \ | ||||||
|  |     librdkafka-dev | ||||||
|  |  | ||||||
| FROM build-base AS poco-build |  | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json |  | ||||||
| RUN git clone https://github.com/stephb9959/poco /poco | RUN git clone https://github.com/stephb9959/poco /poco | ||||||
|  |  | ||||||
| WORKDIR /poco |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN cmake --build . --config Release -j8 |  | ||||||
| RUN cmake --build . --target install |  | ||||||
|  |  | ||||||
| FROM build-base AS cppkafka-build |  | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json |  | ||||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | ||||||
|  | RUN git clone https://github.com/nlohmann/json /json | ||||||
| WORKDIR /cppkafka |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN cmake --build . --config Release -j8 |  | ||||||
| RUN cmake --build . --target install |  | ||||||
|  |  | ||||||
| FROM build-base AS json-schema-validator-build |  | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json |  | ||||||
| RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | ||||||
|  |  | ||||||
| WORKDIR /json-schema-validator |  | ||||||
| RUN mkdir cmake-build |  | ||||||
| WORKDIR cmake-build |  | ||||||
| RUN cmake .. |  | ||||||
| RUN make |  | ||||||
| RUN make install |  | ||||||
|  |  | ||||||
| FROM build-base AS aws-sdk-cpp-build |  | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json |  | ||||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | ||||||
|  |  | ||||||
| WORKDIR /aws-sdk-cpp | WORKDIR /aws-sdk-cpp | ||||||
| @@ -58,31 +25,48 @@ RUN cmake .. -DBUILD_ONLY="sns;s3" \ | |||||||
| RUN cmake --build . --config Release -j8 | RUN cmake --build . --config Release -j8 | ||||||
| RUN cmake --build . --target install | RUN cmake --build . --target install | ||||||
|  |  | ||||||
| FROM build-base AS owsec-build | WORKDIR /cppkafka | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN cmake --build . --config Release -j8 | ||||||
|  | RUN cmake --build . --target install | ||||||
|  |  | ||||||
|  | WORKDIR /poco | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN cmake --build . --config Release -j8 | ||||||
|  | RUN cmake --build . --target install | ||||||
|  |  | ||||||
|  | WORKDIR /json | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN make | ||||||
|  | RUN make install | ||||||
|  |  | ||||||
|  | WORKDIR /json-schema-validator | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN make | ||||||
|  | RUN make install | ||||||
|  |  | ||||||
|  |  | ||||||
| ADD CMakeLists.txt build /owsec/ | ADD CMakeLists.txt build /owsec/ | ||||||
| ADD cmake /owsec/cmake | ADD cmake /owsec/cmake | ||||||
| ADD src /owsec/src | ADD src /owsec/src | ||||||
| ADD .git /owsec/.git | ADD .git /owsec/.git | ||||||
|  |  | ||||||
| COPY --from=poco-build /usr/local/include /usr/local/include |  | ||||||
| COPY --from=poco-build /usr/local/lib /usr/local/lib |  | ||||||
| COPY --from=cppkafka-build /usr/local/include /usr/local/include |  | ||||||
| COPY --from=cppkafka-build /usr/local/lib /usr/local/lib |  | ||||||
| COPY --from=json-schema-validator-build /usr/local/include /usr/local/include |  | ||||||
| COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib |  | ||||||
| COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include |  | ||||||
| COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib |  | ||||||
|  |  | ||||||
| WORKDIR /owsec | WORKDIR /owsec | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| WORKDIR /owsec/cmake-build | WORKDIR /owsec/cmake-build | ||||||
| RUN cmake .. \ | RUN cmake .. | ||||||
|           -Dcrypto_LIBRARY=/usr/lib/libcrypto.so \ |  | ||||||
|           -DBUILD_SHARED_LIBS=ON |  | ||||||
| RUN cmake --build . --config Release -j8 | RUN cmake --build . --config Release -j8 | ||||||
|  |  | ||||||
| FROM alpine:3.15 | FROM alpine | ||||||
|  |  | ||||||
| ENV OWSEC_USER=owsec \ | ENV OWSEC_USER=owsec \ | ||||||
|     OWSEC_ROOT=/owsec-data \ |     OWSEC_ROOT=/owsec-data \ | ||||||
| @@ -94,12 +78,13 @@ RUN addgroup -S "$OWSEC_USER" && \ | |||||||
| RUN mkdir /openwifi | RUN mkdir /openwifi | ||||||
| RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ | RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ | ||||||
|     chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" |     chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" | ||||||
|  | RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl postgresql-client | ||||||
| RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \ | COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec | ||||||
|     mariadb-connector-c libpq unixodbc postgresql-client | COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/ | ||||||
|  | COPY --from=builder /poco/cmake-build/lib/* /lib/ | ||||||
| COPY readiness_check /readiness_check | COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /lib/ | ||||||
| COPY test_scripts/curl/cli /cli | COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /lib/ | ||||||
|  | COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /lib/ | ||||||
|  |  | ||||||
| COPY owsec.properties.tmpl / | COPY owsec.properties.tmpl / | ||||||
| COPY wwwassets /dist/wwwassets | COPY wwwassets /dist/wwwassets | ||||||
| @@ -109,12 +94,8 @@ COPY wait-for-postgres.sh / | |||||||
| RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | ||||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem |     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem | ||||||
|  |  | ||||||
| COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec | COPY readiness_check /readiness_check | ||||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib/ | COPY test_scripts/curl/cli /cli | ||||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib/ |  | ||||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib |  | ||||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib |  | ||||||
| COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib |  | ||||||
|  |  | ||||||
| EXPOSE 16001 17001 16101 | EXPOSE 16001 17001 16101 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| @@ -218,8 +218,8 @@ This is the FQDN used externally serving the OpenAPI interface. | |||||||
| `owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so, | `owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so, | ||||||
| an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS | an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS | ||||||
|  |  | ||||||
| #### AWS SMS | #### AWS SNS | ||||||
| For SNS you must create an IAM ID that has sns:sendmessage rights.   | For SNS you must create an IAM ID that has sns:sendmessage rights.  | ||||||
|  |  | ||||||
| ```asm | ```asm | ||||||
| smssender.provider = aws | smssender.provider = aws | ||||||
| @@ -252,13 +252,3 @@ mailer.loginmethod = login | |||||||
| mailer.port = 587 | mailer.port = 587 | ||||||
| mailer.templates = $OWSEC_ROOT/templates | mailer.templates = $OWSEC_ROOT/templates | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Google Authenticator |  | ||||||
| In order to use the Google Time-based One-Time Password (TOTP), the user must 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 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| It is very important that you not use spaces in your OrgName. |  | ||||||
| @@ -25,18 +25,9 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; t | |||||||
|   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ |   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ | ||||||
|   SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ |   SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ | ||||||
|   SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ |   SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ | ||||||
|   SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \ |   MAILER_HOSTNAME=${MAILER_HOSTNAME:-"smtp.gmail.com"} \ | ||||||
|   SMSSENDER_PROVIDER=${SMSSENDER_PROVIDER:-""} \ |   MAILER_USERNAME=${MAILER_USERNAME:-"************************"} \ | ||||||
|   SMSSENDER_AWS_SECRETKEY=${SMSSENDER_AWS_SECRETKEY:-""} \ |   MAILER_PASSWORD=${MAILER_PASSWORD:-"************************"} \ | ||||||
|   SMSSENDER_AWS_ACCESSKEY=${SMSSENDER_AWS_ACCESSKEY:-""} \ |  | ||||||
|   SMSSENDER_AWS_REGION=${SMSSENDER_AWS_REGION:-""} \ |  | ||||||
|   SMSSENDER_TWILIO_SID=${SMSSENDER_TWILIO_SID:-""} \ |  | ||||||
|   SMSSENDER_TWILIO_TOKEN=${SMSSENDER_TWILIO_TOKEN:-""} \ |  | ||||||
|   SMSSENDER_TWILIO_PHONENUMBER=${SMSSENDER_TWILIO_PHONENUMBER:-""} \ |  | ||||||
|   MAILER_ENABLED=${MAILER_ENABLED:-"false"} \ |  | ||||||
|   MAILER_HOSTNAME=${MAILER_HOSTNAME:-"localhost"} \ |  | ||||||
|   MAILER_USERNAME=${MAILER_USERNAME:-""} \ |  | ||||||
|   MAILER_PASSWORD=${MAILER_PASSWORD:-""} \ |  | ||||||
|   MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \ |   MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \ | ||||||
|   MAILER_PORT=${MAILER_PORT:-"587"} \ |   MAILER_PORT=${MAILER_PORT:-"587"} \ | ||||||
|   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ |   MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ | ||||||
|   | |||||||
| @@ -5,14 +5,14 @@ name: owsec | |||||||
| version: 0.1.0 | version: 0.1.0 | ||||||
| dependencies: | dependencies: | ||||||
| - name: postgresql | - name: postgresql | ||||||
|   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ |   repository: https://charts.bitnami.com/bitnami | ||||||
|   version: 10.9.2 |   version: 10.9.2 | ||||||
|   condition: postgresql.enabled |   condition: postgresql.enabled | ||||||
| - name: mysql | - name: mysql | ||||||
|   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ |   repository: https://charts.bitnami.com/bitnami | ||||||
|   version: 8.8.3 |   version: 8.8.3 | ||||||
|   condition: mysql.enabled |   condition: mysql.enabled | ||||||
| - name: mariadb | - name: mariadb | ||||||
|   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ |   repository: https://charts.bitnami.com/bitnami | ||||||
|   version: 9.4.2 |   version: 9.4.2 | ||||||
|   condition: mariadb.enabled |   condition: mariadb.enabled | ||||||
|   | |||||||
| @@ -30,13 +30,3 @@ Create chart name and version as used by the chart label. | |||||||
| {{- define "owsec.chart" -}} | {{- define "owsec.chart" -}} | ||||||
| {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} | ||||||
| {{- end -}} | {{- end -}} | ||||||
|  |  | ||||||
| {{- define "owsec.ingress.apiVersion" -}} |  | ||||||
|   {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}} |  | ||||||
|       {{- print "networking.k8s.io/v1" -}} |  | ||||||
|   {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}} |  | ||||||
|     {{- print "networking.k8s.io/v1beta1" -}} |  | ||||||
|   {{- else -}} |  | ||||||
|     {{- print "extensions/v1beta1" -}} |  | ||||||
|   {{- end -}} |  | ||||||
| {{- end -}} |  | ||||||
|   | |||||||
| @@ -13,7 +13,6 @@ spec: | |||||||
|   replicas: {{ .Values.replicaCount }} |   replicas: {{ .Values.replicaCount }} | ||||||
|   strategy: |   strategy: | ||||||
|     type: {{ .Values.strategyType }} |     type: {{ .Values.strategyType }} | ||||||
|   revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} |  | ||||||
|   selector: |   selector: | ||||||
|     matchLabels: |     matchLabels: | ||||||
|       app.kubernetes.io/name: {{ include "owsec.name" . }} |       app.kubernetes.io/name: {{ include "owsec.name" . }} | ||||||
| @@ -36,16 +35,6 @@ spec: | |||||||
|         {{- end }} |         {{- end }} | ||||||
|     spec: |     spec: | ||||||
|  |  | ||||||
|       initContainers: |  | ||||||
|         - name: wait-kafka |  | ||||||
|           image: "{{ .Values.images.dockerize.repository }}:{{ .Values.images.dockerize.tag }}" |  | ||||||
|           imagePullPolicy: {{ .Values.images.dockerize.pullPolicy }} |  | ||||||
|           args: |  | ||||||
|             - -wait |  | ||||||
|             - tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }} |  | ||||||
|             - -timeout |  | ||||||
|             - 600s |  | ||||||
|  |  | ||||||
|       containers: |       containers: | ||||||
|  |  | ||||||
|         - name: owsec |         - name: owsec | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| {{- range $ingress, $ingressValue := .Values.ingresses }} | {{- range $ingress, $ingressValue := .Values.ingresses }} | ||||||
| {{- if $ingressValue.enabled }} | {{- if $ingressValue.enabled }} | ||||||
| --- | --- | ||||||
| apiVersion: {{ include "owsec.ingress.apiVersion" $root }} | apiVersion: extensions/v1beta1 | ||||||
| kind: Ingress | kind: Ingress | ||||||
| metadata: | metadata: | ||||||
|   name: {{ include "owsec.fullname" $root }}-{{ $ingress }} |   name: {{ include "owsec.fullname" $root }}-{{ $ingress }} | ||||||
| @@ -36,23 +36,9 @@ spec: | |||||||
|       paths: |       paths: | ||||||
|       {{- range $ingressValue.paths }} |       {{- range $ingressValue.paths }} | ||||||
|         - path: {{ .path }} |         - path: {{ .path }} | ||||||
|           {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }} |  | ||||||
|           pathType: {{ .pathType | default "ImplementationSpecific" }} |  | ||||||
|           {{- end }} |  | ||||||
|           backend: |           backend: | ||||||
|             {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }} |  | ||||||
|             service: |  | ||||||
|               name: {{ include "owsec.fullname" $root }}-{{ .serviceName }} |  | ||||||
|               port: |  | ||||||
|               {{- if kindIs "string" .servicePort }} |  | ||||||
|                 name: {{ .servicePort }} |  | ||||||
|               {{- else }} |  | ||||||
|                 number: {{ .servicePort }} |  | ||||||
|               {{- end }} |  | ||||||
|             {{- else }} |  | ||||||
|             serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }} |             serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }} | ||||||
|             servicePort: {{ .servicePort }} |             servicePort: {{ .servicePort }} | ||||||
|             {{- end }} |  | ||||||
|       {{- end }} |       {{- end }} | ||||||
|   {{- end }} |   {{- end }} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| # System | # System | ||||||
| replicaCount: 1 | replicaCount: 1 | ||||||
| strategyType: Recreate | strategyType: Recreate | ||||||
| revisionHistoryLimit: 2 |  | ||||||
|  |  | ||||||
| nameOverride: "" | nameOverride: "" | ||||||
| fullnameOverride: "" | fullnameOverride: "" | ||||||
| @@ -9,20 +8,16 @@ fullnameOverride: "" | |||||||
| images: | images: | ||||||
|   owsec: |   owsec: | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||||
|     tag: v2.5.2 |     tag: v2.4.0 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
| #      username: username | #      username: username | ||||||
| #      password: password | #      password: password | ||||||
|   dockerize: |  | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize |  | ||||||
|     tag: 0.16.0 |  | ||||||
|     pullPolicy: IfNotPresent |  | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   owsec: |   owsec: | ||||||
|     type: ClusterIP |     type: LoadBalancer | ||||||
|     ports: |     ports: | ||||||
|       restapi: |       restapi: | ||||||
|         servicePort: 16001 |         servicePort: 16001 | ||||||
| @@ -43,6 +38,7 @@ checks: | |||||||
|       exec: |       exec: | ||||||
|         command: |         command: | ||||||
|           - /readiness_check |           - /readiness_check | ||||||
|  |       failureThreshold: 1 | ||||||
|  |  | ||||||
| ingresses: | ingresses: | ||||||
|   restapi: |   restapi: | ||||||
| @@ -54,7 +50,6 @@ ingresses: | |||||||
|     - restapi.chart-example.local |     - restapi.chart-example.local | ||||||
|     paths: |     paths: | ||||||
|     - path: / |     - path: / | ||||||
|       pathType: ImplementationSpecific |  | ||||||
|       serviceName: owsec |       serviceName: owsec | ||||||
|       servicePort: restapi |       servicePort: restapi | ||||||
|  |  | ||||||
| @@ -146,17 +141,11 @@ configProperties: | |||||||
|   authentication.default.access: master |   authentication.default.access: master | ||||||
|   authentication.service.type: internal |   authentication.service.type: internal | ||||||
|   # Mailer |   # Mailer | ||||||
|   mailer.enabled: "false" |  | ||||||
|   mailer.hostname: smtp.gmail.com |   mailer.hostname: smtp.gmail.com | ||||||
|   mailer.sender: OpenWIFI |   mailer.sender: OpenWIFI | ||||||
|   mailer.loginmethod: login |   mailer.loginmethod: login | ||||||
|   mailer.port: 587 |   mailer.port: 587 | ||||||
|   mailer.templates: $OWSEC_ROOT/persist/templates |   mailer.templates: $OWSEC_ROOT/persist/templates | ||||||
|   # SMS |  | ||||||
|   smssender.enabled: "false" |  | ||||||
|   smssender.provider: "aws" |  | ||||||
|   #smssender.aws.region: "" |  | ||||||
|   #smssender.twilio.phonenumber: "" |  | ||||||
|   # ALB |   # ALB | ||||||
|   alb.enable: "true" |   alb.enable: "true" | ||||||
|   alb.port: 16101 |   alb.port: 16101 | ||||||
| @@ -196,9 +185,22 @@ configProperties: | |||||||
|   openwifi.system.uri.ui: https://localhost |   openwifi.system.uri.ui: https://localhost | ||||||
|   openwifi.system.commandchannel: /tmp/app_owsec |   openwifi.system.commandchannel: /tmp/app_owsec | ||||||
|   # Logging |   # Logging | ||||||
|   logging.type: console |   logging.formatters.f1.class: PatternFormatter | ||||||
|   logging.path: $OWSEC_ROOT/logs |   logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t" | ||||||
|   logging.level: debug |   logging.formatters.f1.times: UTC | ||||||
|  |   logging.channels.c1.class: ConsoleChannel | ||||||
|  |   logging.channels.c1.formatter: f1 | ||||||
|  |   logging.channels.c2.class: FileChannel | ||||||
|  |   logging.channels.c2.path: /tmp/log_owsec | ||||||
|  |   logging.channels.c2.formatter.class: PatternFormatter | ||||||
|  |   logging.channels.c2.formatter.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t" | ||||||
|  |   logging.channels.c2.rotation: "20 M" | ||||||
|  |   logging.channels.c2.archive: timestamp | ||||||
|  |   logging.channels.c2.purgeCount: 20 | ||||||
|  |   logging.channels.c3.class: ConsoleChannel | ||||||
|  |   logging.channels.c3.pattern: "%s: [%p] %t" | ||||||
|  |   logging.loggers.root.channel: c1 | ||||||
|  |   logging.loggers.root.level: debug | ||||||
|  |  | ||||||
|   # -> Secret part |   # -> Secret part | ||||||
|   # REST API |   # REST API | ||||||
| @@ -210,12 +212,6 @@ configProperties: | |||||||
|   # Mailer |   # Mailer | ||||||
|   mailer.username: no-reply@arilia.com |   mailer.username: no-reply@arilia.com | ||||||
|   mailer.password: "**************************" |   mailer.password: "**************************" | ||||||
|   # SMS |  | ||||||
|   #smssender.aws.secretkey: "" |  | ||||||
|   #smssender.aws.accesskey: "" |  | ||||||
|   #smssender.twilio.sid: "" |  | ||||||
|   #smssender.twilio.token: "" |  | ||||||
|   # |  | ||||||
|   # Storage |   # Storage | ||||||
|   ## PostgreSQL |   ## PostgreSQL | ||||||
|   storage.type.postgresql.username: stephb |   storage.type.postgresql.username: stephb | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ openapi: 3.0.1 | |||||||
| info: | info: | ||||||
|   title: uCentral Security API |   title: uCentral Security API | ||||||
|   description: A process to manage security logins. |   description: A process to manage security logins. | ||||||
|   version: 2.5.0 |   version: 2.0.0 | ||||||
|   license: |   license: | ||||||
|     name: BSD3 |     name: BSD3 | ||||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE |     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||||
| @@ -61,11 +61,8 @@ components: | |||||||
|                   - 6     # INTERNAL_ERROR, |                   - 6     # INTERNAL_ERROR, | ||||||
|                   - 7     # ACCESS_DENIED, |                   - 7     # ACCESS_DENIED, | ||||||
|                   - 8     # INVALID_TOKEN |                   - 8     # INVALID_TOKEN | ||||||
|                   - 9     # EXPIRED_TOKEN |                   - 9     # expired token | ||||||
|                   - 10    # RATE_LIMIT_EXCEEDED |                   - 10    # rate limit exceeded | ||||||
|                   - 11    # BAD_MFA_TRANSACTION |  | ||||||
|                   - 12    # MFA_FAILURE |  | ||||||
|                   - 13    # SECURITY_SERVICE_UNREACHABLE |  | ||||||
|               ErrorDetails: |               ErrorDetails: | ||||||
|                 type: string |                 type: string | ||||||
|               ErrorDescription: |               ErrorDescription: | ||||||
| @@ -84,20 +81,8 @@ components: | |||||||
|               Code: |               Code: | ||||||
|                 type: integer |                 type: integer | ||||||
| 
 | 
 | ||||||
|     BadRequest: |  | ||||||
|       description: The requested operation failed. |  | ||||||
|       content: |  | ||||||
|         application/json: |  | ||||||
|           schema: |  | ||||||
|             properties: |  | ||||||
|               ErrorCode: |  | ||||||
|                 type: integer |  | ||||||
|               ErrorDetails: |  | ||||||
|                 type: string |  | ||||||
|               ErrorDescription: |  | ||||||
|                 type: integer |  | ||||||
| 
 |  | ||||||
|   schemas: |   schemas: | ||||||
|  | 
 | ||||||
|     WebTokenRequest: |     WebTokenRequest: | ||||||
|       description: User Id and password. |       description: User Id and password. | ||||||
|       type: object |       type: object | ||||||
| @@ -243,7 +228,7 @@ components: | |||||||
|           enum: |           enum: | ||||||
|             - sms |             - sms | ||||||
|             - email |             - email | ||||||
|             - authenticator |             - voice | ||||||
| 
 | 
 | ||||||
|     UserLoginLoginExtensions: |     UserLoginLoginExtensions: | ||||||
|       type: object |       type: object | ||||||
| @@ -252,8 +237,6 @@ components: | |||||||
|           type: array |           type: array | ||||||
|           items: |           items: | ||||||
|             $ref: '#/components/schemas/MobilePhoneNumber' |             $ref: '#/components/schemas/MobilePhoneNumber' | ||||||
|         authenticatorSecret: |  | ||||||
|           type: string |  | ||||||
|         mfa: |         mfa: | ||||||
|           $ref: '#/components/schemas/MfaAuthInfo' |           $ref: '#/components/schemas/MfaAuthInfo' | ||||||
| 
 | 
 | ||||||
| @@ -350,9 +333,6 @@ components: | |||||||
|         securityPolicyChange: |         securityPolicyChange: | ||||||
|           type: integer |           type: integer | ||||||
|           format: int64 |           format: int64 | ||||||
|         modified: |  | ||||||
|           type: integer |  | ||||||
|           format: int64 |  | ||||||
|         userTypeProprietaryInfo: |         userTypeProprietaryInfo: | ||||||
|           $ref: '#/components/schemas/UserLoginLoginExtensions' |           $ref: '#/components/schemas/UserLoginLoginExtensions' | ||||||
| 
 | 
 | ||||||
| @@ -413,24 +393,6 @@ components: | |||||||
|         answer: |         answer: | ||||||
|           type: string |           type: string | ||||||
| 
 | 
 | ||||||
|     SubMfaConfig: |  | ||||||
|       type: object |  | ||||||
|       properties: |  | ||||||
|         id: |  | ||||||
|           type: string |  | ||||||
|           format: uuid |  | ||||||
|         type: |  | ||||||
|           type: string |  | ||||||
|           enum: |  | ||||||
|             - disabled |  | ||||||
|             - sms |  | ||||||
|             - email |  | ||||||
|         email: |  | ||||||
|           type: string |  | ||||||
|           format: email |  | ||||||
|         sms: |  | ||||||
|           type: string |  | ||||||
| 
 |  | ||||||
|     ######################################################################################### |     ######################################################################################### | ||||||
|     ## |     ## | ||||||
|     ## These are endpoints that all services in the uCentral stack must provide |     ## These are endpoints that all services in the uCentral stack must provide | ||||||
| @@ -675,22 +637,6 @@ components: | |||||||
|           items: |           items: | ||||||
|             $ref: '#/components/schemas/TagValuePair' |             $ref: '#/components/schemas/TagValuePair' | ||||||
| 
 | 
 | ||||||
|     Preferences: |  | ||||||
|       type: object |  | ||||||
|       properties: |  | ||||||
|         modified: |  | ||||||
|           type: integer |  | ||||||
|           format: int64 |  | ||||||
|         data: |  | ||||||
|           type: array |  | ||||||
|           items: |  | ||||||
|             type: object |  | ||||||
|             properties: |  | ||||||
|               tag: |  | ||||||
|                 type: string |  | ||||||
|               value: |  | ||||||
|                 type: string |  | ||||||
| 
 |  | ||||||
|     ######################################################################################### |     ######################################################################################### | ||||||
|     ## |     ## | ||||||
|     ## End of uCentral system wide values |     ## End of uCentral system wide values | ||||||
| @@ -756,64 +702,6 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|   /suboauth2: |  | ||||||
|     post: |  | ||||||
|       tags: |  | ||||||
|         - Authentication |  | ||||||
|       summary: Get access token - to be used as Bearer token header for all other API requests. |  | ||||||
|       operationId: getSubAccessToken |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: newPassword |  | ||||||
|           description: used when a user is trying to change her password. This will be the new password. |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: forgotPassword |  | ||||||
|           description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: requirements |  | ||||||
|           description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: resendMFACode |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: completeMFAChallenge |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|       requestBody: |  | ||||||
|         description: User id and password |  | ||||||
|         required: true |  | ||||||
|         content: |  | ||||||
|           application/json: |  | ||||||
|             schema: |  | ||||||
|               oneOf: |  | ||||||
|                 - $ref: '#/components/schemas/WebTokenRequest' |  | ||||||
|                 - $ref: '#/components/schemas/MFAChallengeResponse' |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           description: successful operation |  | ||||||
|           content: |  | ||||||
|             application/json: |  | ||||||
|               schema: |  | ||||||
|                 oneOf: |  | ||||||
|                   - $ref: '#/components/schemas/WebTokenResult' |  | ||||||
|                   - $ref: '#/components/schemas/MFAChallengeRequest' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|   /oauth2/{token}: |   /oauth2/{token}: | ||||||
|     delete: |     delete: | ||||||
|       tags: |       tags: | ||||||
| @@ -839,31 +727,6 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|   /suboauth2/{token}: |  | ||||||
|     delete: |  | ||||||
|       tags: |  | ||||||
|         - Authentication |  | ||||||
|       summary: Revoke a token. |  | ||||||
|       operationId: removeSubAccessToken |  | ||||||
|       parameters: |  | ||||||
|         - in: path |  | ||||||
|           name: token |  | ||||||
|           schema: |  | ||||||
|             type: |  | ||||||
|               string |  | ||||||
|           required: true |  | ||||||
|       responses: |  | ||||||
|         204: |  | ||||||
|           description: successful operation |  | ||||||
|           content: |  | ||||||
|             application/json: |  | ||||||
|               schema: |  | ||||||
|                 $ref: '#/components/responses/Success' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|   /systemEndpoints: |   /systemEndpoints: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
| @@ -928,52 +791,6 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|   /subusers: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - Subscribers |  | ||||||
|       summary: Retrieve a list of existing users as well as some information about them. |  | ||||||
|       operationId: getSubUsers |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: offset |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: limit |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           description: Selecting this option means the newest record will be returned. Use limit to select how many. |  | ||||||
|           name: filter |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           description: Return only the ids. |  | ||||||
|           name: idOnly |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           description: Return only the ids. |  | ||||||
|           name: select |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|             example: id1,id2,id3,id4,id5 |  | ||||||
|           required: false |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/UserList' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|   /user/{id}: |   /user/{id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
| @@ -1078,110 +895,6 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|   /subuser/{id}: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - Subscribers |  | ||||||
|       operationId: getSubUser |  | ||||||
|       summary: Retrieve the information for a single user. |  | ||||||
|       parameters: |  | ||||||
|         - in: path |  | ||||||
|           name: id |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|             format: uuid |  | ||||||
|           required: true |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/UserInfo' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|     delete: |  | ||||||
|       tags: |  | ||||||
|         - Subscribers |  | ||||||
|       operationId: deleteSubUser |  | ||||||
|       summary: Delete a single user. |  | ||||||
|       parameters: |  | ||||||
|         - in: path |  | ||||||
|           name: id |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: true |  | ||||||
|       responses: |  | ||||||
|         204: |  | ||||||
|           $ref: '#/components/responses/Success' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|     post: |  | ||||||
|       tags: |  | ||||||
|         - Subscribers |  | ||||||
|       operationId: createSubUser |  | ||||||
|       summary: Create a single user. |  | ||||||
|       parameters: |  | ||||||
|         - in: path |  | ||||||
|           name: id |  | ||||||
|           #must be set to 0 for user creation |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: true |  | ||||||
|         - in: query |  | ||||||
|           name: email_verification |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|       requestBody: |  | ||||||
|         description: User details (some fields are ignored during creation) |  | ||||||
|         content: |  | ||||||
|           application/json: |  | ||||||
|             schema: |  | ||||||
|               $ref: '#/components/schemas/UserInfo' |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/UserInfo' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|     put: |  | ||||||
|       tags: |  | ||||||
|         - Subscribers |  | ||||||
|       operationId: updateSubUser |  | ||||||
|       summary: Modify a single user. |  | ||||||
|       parameters: |  | ||||||
|         - in: path |  | ||||||
|           name: id |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: true |  | ||||||
|         - in: query |  | ||||||
|           name: email_verification |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|       requestBody: |  | ||||||
|         description: User details (some fields are ignored during update) |  | ||||||
|         content: |  | ||||||
|           application/json: |  | ||||||
|             schema: |  | ||||||
|               $ref: '#/components/schemas/UserInfo' |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/UserInfo' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|   /avatar/{id}: |   /avatar/{id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
| @@ -1352,138 +1065,6 @@ paths: | |||||||
|                     items: |                     items: | ||||||
|                       type: string |                       type: string | ||||||
| 
 | 
 | ||||||
|   /userPreferences: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - Preferences |  | ||||||
|       operationId: getUserPreferences |  | ||||||
|       summary: Get the list of recorded preferences for a user |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/Preferences' |  | ||||||
|         400: |  | ||||||
|           $ref: '#/components/responses/BadRequest' |  | ||||||
|     post: |  | ||||||
|       tags: |  | ||||||
|         - Preferences |  | ||||||
|       operationId: setUserPreferences |  | ||||||
|       summary: Set the list of recorded preferences for a user |  | ||||||
|       requestBody: |  | ||||||
|         description: Setting the list of preferences |  | ||||||
|         content: |  | ||||||
|           application/json: |  | ||||||
|             schema: |  | ||||||
|               $ref: '#/components/schemas/Preferences' |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/Preferences' |  | ||||||
|         400: |  | ||||||
|           $ref: '#/components/responses/BadRequest' |  | ||||||
| 
 |  | ||||||
|   /submfa: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - MFA |  | ||||||
|       summary: Retrieve the cyrrent setting for MFA |  | ||||||
|       operationId: getMFS |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/SubMfaConfig' |  | ||||||
| 
 |  | ||||||
|     put: |  | ||||||
|       tags: |  | ||||||
|         - MFA |  | ||||||
|       summary: Retrieve the cyrrent setting for MFA |  | ||||||
|       operationId: modifyMFS |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: startValidation |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: completeValidation |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |  | ||||||
|           name: challengeCode |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|           required: false |  | ||||||
|       requestBody: |  | ||||||
|         content: |  | ||||||
|           application/json: |  | ||||||
|             schema: |  | ||||||
|               $ref: '#/components/schemas/SubMfaConfig' |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/SubMfaConfig' |  | ||||||
|         400: |  | ||||||
|           $ref: '#/components/responses/BadRequest' |  | ||||||
| 
 |  | ||||||
|   /totp: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - Security |  | ||||||
|       summary: Retrieve the Authenticator QR Code |  | ||||||
|       operationId: getTotpQrCode |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: reset |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|             default: false |  | ||||||
|           required: false |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           description: QRCode |  | ||||||
|           content: |  | ||||||
|             image/svg+xml: |  | ||||||
|               schema: |  | ||||||
|                 type: string |  | ||||||
|                 format: binary |  | ||||||
|         400: |  | ||||||
|           $ref: '#/components/responses/BadRequest' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
| 
 |  | ||||||
|     put: |  | ||||||
|       tags: |  | ||||||
|         - Security |  | ||||||
|       summary: Send the first security code to validate your setup |  | ||||||
|       operationId: sendToptTestCode |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: value |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: true |  | ||||||
|         - in: query |  | ||||||
|           name: index |  | ||||||
|           schema: |  | ||||||
|             type: integer |  | ||||||
|             format: int64 |  | ||||||
|           required: required |  | ||||||
|           example: 1,2,3 |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           description: Succesful posting of response. |  | ||||||
|           content: |  | ||||||
|             application/json: |  | ||||||
|               schema: |  | ||||||
|                 type: object |  | ||||||
|                 properties: |  | ||||||
|                   nextIndex: |  | ||||||
|                     type: integer |  | ||||||
|                   moreCodes: |  | ||||||
|                     type: boolean |  | ||||||
|         400: |  | ||||||
|           $ref: '#/components/responses/BadRequest' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
| 
 |  | ||||||
|   ######################################################################################### |   ######################################################################################### | ||||||
|   ## |   ## | ||||||
|   ## These are endpoints that all services in the uCentral stack must provide |   ## These are endpoints that all services in the uCentral stack must provide | ||||||
| @@ -1559,27 +1140,6 @@ paths: | |||||||
|         404: |         404: | ||||||
|           $ref: '#/components/responses/NotFound' |           $ref: '#/components/responses/NotFound' | ||||||
| 
 | 
 | ||||||
|   /validateSubToken: |  | ||||||
|     get: |  | ||||||
|       tags: |  | ||||||
|         - Security |  | ||||||
|         - Subscribers |  | ||||||
|       summary: Allows any microservice to validate a token and get security policy for a specific user. |  | ||||||
|       operationId: validateSubToken |  | ||||||
|       parameters: |  | ||||||
|         - in: query |  | ||||||
|           name: token |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|           required: true |  | ||||||
|       responses: |  | ||||||
|         200: |  | ||||||
|           $ref: '#/components/schemas/TokenValidationResult' |  | ||||||
|         403: |  | ||||||
|           $ref: '#/components/responses/Unauthorized' |  | ||||||
|         404: |  | ||||||
|           $ref: '#/components/responses/NotFound' |  | ||||||
| 
 |  | ||||||
|   /system: |   /system: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
| @@ -86,7 +86,6 @@ openwifi.document.policy.access = /wwwassets/access_policy.html | |||||||
| openwifi.document.policy.password = /wwwassets/password_policy.html | openwifi.document.policy.password = /wwwassets/password_policy.html | ||||||
| openwifi.avatar.maxsize = 2000000 | openwifi.avatar.maxsize = 2000000 | ||||||
|  |  | ||||||
| totp.issuer = OpenWiFi |  | ||||||
| # | # | ||||||
| # This section select which form of persistence you need | # This section select which form of persistence you need | ||||||
| # Only one selected at a time. If you select multiple, this service will die if a horrible | # Only one selected at a time. If you select multiple, this service will die if a horrible | ||||||
| @@ -119,12 +118,44 @@ storage.type.mysql.database = ucentral | |||||||
| storage.type.mysql.port = 3306 | storage.type.mysql.port = 3306 | ||||||
| storage.type.mysql.connectiontimeout = 60 | storage.type.mysql.connectiontimeout = 60 | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################################################################## | ######################################################################## | ||||||
| ######################################################################## | ######################################################################## | ||||||
| # | # | ||||||
| # Logging: please leave as is for now. | # Logging: please leave as is for now. | ||||||
| # | # | ||||||
| ######################################################################## | ######################################################################## | ||||||
| logging.type = file | logging.formatters.f1.class = PatternFormatter | ||||||
| logging.path = $OWSEC_ROOT/logs | logging.formatters.f1.pattern = %s: [%p] %t | ||||||
| logging.level = debug | logging.formatters.f1.times = UTC | ||||||
|  | logging.channels.c1.class = ConsoleChannel | ||||||
|  | logging.channels.c1.formatter = f1 | ||||||
|  |  | ||||||
|  | # This is where the logs will be written. This path MUST exist | ||||||
|  | logging.channels.c2.class = FileChannel | ||||||
|  | logging.channels.c2.path = $OWSEC_ROOT/logs/log | ||||||
|  | logging.channels.c2.formatter.class = PatternFormatter | ||||||
|  | logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t | ||||||
|  | logging.channels.c2.rotation = 20 M | ||||||
|  | logging.channels.c2.archive = timestamp | ||||||
|  | logging.channels.c2.purgeCount = 20 | ||||||
|  | logging.channels.c3.class = ConsoleChannel | ||||||
|  | logging.channels.c3.pattern = %s: [%p] %t | ||||||
|  |  | ||||||
|  | # External Channel | ||||||
|  | logging.loggers.root.channel = c2 | ||||||
|  | logging.loggers.root.level = debug | ||||||
|  |  | ||||||
|  | # Inline Channel with PatternFormatter | ||||||
|  | # logging.loggers.l1.name = logger1 | ||||||
|  | # logging.loggers.l1.channel.class = ConsoleChannel | ||||||
|  | # logging.loggers.l1.channel.pattern = %s: [%p] %t | ||||||
|  | # logging.loggers.l1.level = information | ||||||
|  | # SplitterChannel | ||||||
|  | # logging.channels.splitter.class = SplitterChannel | ||||||
|  | # logging.channels.splitter.channels = l1,l2 | ||||||
|  | # logging.loggers.l2.name = logger2 | ||||||
|  | # logging.loggers.l2.channel = splitter | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,21 +40,9 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec | |||||||
| openwifi.service.key = ${SERVICE_KEY} | openwifi.service.key = ${SERVICE_KEY} | ||||||
| openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} | openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} | ||||||
|  |  | ||||||
| smssender.enabled = ${SMSSENDER_ENABLED} |  | ||||||
| smssender.provider = ${SMSSENDER_PROVIDER} |  | ||||||
|  |  | ||||||
| smssender.aws.secretkey = ${SMSSENDER_AWS_SECRETKEY} |  | ||||||
| smssender.aws.accesskey = ${SMSSENDER_AWS_ACCESSKEY} |  | ||||||
| smssender.aws.region = ${SMSSENDER_AWS_REGION} |  | ||||||
|  |  | ||||||
| smssender.twilio.sid = ${SMSSENDER_TWILIO_SID} |  | ||||||
| smssender.twilio.token = ${SMSSENDER_TWILIO_TOKEN} |  | ||||||
| smssender.twilio.phonenumber = ${SMSSENDER_TWILIO_PHONENUMBER} |  | ||||||
|  |  | ||||||
| # | # | ||||||
| # Security Microservice Specific Section | # Security Microservice Specific Section | ||||||
| # | # | ||||||
| mailer.enabled = ${MAILER_ENABLED} |  | ||||||
| mailer.hostname = ${MAILER_HOSTNAME} | mailer.hostname = ${MAILER_HOSTNAME} | ||||||
| mailer.username = ${MAILER_USERNAME} | mailer.username = ${MAILER_USERNAME} | ||||||
| mailer.password = ${MAILER_PASSWORD} | mailer.password = ${MAILER_PASSWORD} | ||||||
| @@ -122,6 +110,37 @@ storage.type.mysql.connectiontimeout = 60 | |||||||
| # Logging: please leave as is for now. | # Logging: please leave as is for now. | ||||||
| # | # | ||||||
| ######################################################################## | ######################################################################## | ||||||
| logging.type = console | logging.formatters.f1.class = PatternFormatter | ||||||
| logging.path = $OWSEC_ROOT/logs | logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t | ||||||
| logging.level = debug | logging.formatters.f1.times = UTC | ||||||
|  | logging.channels.c1.class = ConsoleChannel | ||||||
|  | logging.channels.c1.formatter = f1 | ||||||
|  |  | ||||||
|  | # This is where the logs will be written. This path MUST exist | ||||||
|  | logging.channels.c2.class = FileChannel | ||||||
|  | logging.channels.c2.path = $OWSEC_ROOT/logs/log | ||||||
|  | logging.channels.c2.formatter.class = PatternFormatter | ||||||
|  | logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t | ||||||
|  | logging.channels.c2.rotation = 20 M | ||||||
|  | logging.channels.c2.archive = timestamp | ||||||
|  | logging.channels.c2.purgeCount = 20 | ||||||
|  | logging.channels.c3.class = ConsoleChannel | ||||||
|  | logging.channels.c3.pattern = %s: [%p] %t | ||||||
|  |  | ||||||
|  | # External Channel | ||||||
|  | logging.loggers.root.channel = c1 | ||||||
|  | logging.loggers.root.level = debug | ||||||
|  |  | ||||||
|  | # Inline Channel with PatternFormatter | ||||||
|  | # logging.loggers.l1.name = logger1 | ||||||
|  | # logging.loggers.l1.channel.class = ConsoleChannel | ||||||
|  | # logging.loggers.l1.channel.pattern = %s: [%p] %t | ||||||
|  | # logging.loggers.l1.level = information | ||||||
|  | # SplitterChannel | ||||||
|  | # logging.channels.splitter.class = SplitterChannel | ||||||
|  | # logging.channels.splitter.channels = l1,l2 | ||||||
|  | # logging.loggers.l2.name = logger2 | ||||||
|  | # logging.loggers.l2.channel = splitter | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,23 +13,22 @@ then | |||||||
|   exit 1 |   exit 1 | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | if [[ "${OWSEC_USERNAME}" == "" ]] | ||||||
|  | then | ||||||
|  |   echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like" | ||||||
|  |   echo "OWSEC_USERNAME=tip@ucentral.com" | ||||||
|  |   exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [[ "${OWSEC_PASSWORD}" == "" ]] | ||||||
|  | then | ||||||
|  |   echo "You must set the variable OWSEC_PASSWORD in order to use this script. Something like" | ||||||
|  |   echo "OWSEC_PASSWORD=openwifi" | ||||||
|  |   exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
| if [[ "${READINESS_METHOD}" == "systeminfo" ]] | if [[ "${READINESS_METHOD}" == "systeminfo" ]] | ||||||
| then | then | ||||||
|   if [[ "${OWSEC_USERNAME}" == "" ]] |  | ||||||
|   then |  | ||||||
|     echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like" |  | ||||||
|     echo "OWSEC_USERNAME=tip@ucentral.com" |  | ||||||
|     exit 1 |  | ||||||
|   fi |  | ||||||
|  |  | ||||||
|   if [[ "${OWSEC_PASSWORD}" == "" ]] |  | ||||||
|   then |  | ||||||
|     echo "You must set the variable OWSEC_PASSWORD in order to use this script. Something like" |  | ||||||
|     echo "OWSEC_PASSWORD=openwifi" |  | ||||||
|     exit 1 |  | ||||||
|   fi |  | ||||||
|  |  | ||||||
|   export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWSEC_CONFIG/owsec.properties | awk -F '=' '{print $2}' | xargs | envsubst) |   export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWSEC_CONFIG/owsec.properties | awk -F '=' '{print $2}' | xargs | envsubst) | ||||||
|   # Get OAuth token from OWSEC and cache it or use cached one |   # Get OAuth token from OWSEC and cache it or use cached one | ||||||
|   payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }" |   payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }" | ||||||
|   | |||||||
| @@ -17,60 +17,21 @@ namespace OpenWifi { | |||||||
|             DELETE, |             DELETE, | ||||||
|             CREATE |             CREATE | ||||||
|         }; |         }; | ||||||
| /* |  | ||||||
|     1) You cannot delete yourself |  | ||||||
|     2) If you are root, you can do anything. |  | ||||||
|     3) You can do anything to yourself |  | ||||||
|     4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT |  | ||||||
|     5) Creation rules: |  | ||||||
|         ROOT -> create anything |  | ||||||
|         PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning |  | ||||||
|         ADMIN -> admin-subs-csr-installer-noc-accounting |  | ||||||
|         ACCOUNTING -> subs-installer-csr |  | ||||||
|  |  | ||||||
|  */ |  | ||||||
|         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { |         static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) { | ||||||
|             //  rule 1 |             if(User.Id == Target.Id && Op==DELETE) | ||||||
|             if(User.id == Target.id && Op==DELETE) |  | ||||||
|                 return false; |                 return false; | ||||||
|  |  | ||||||
|             //  rule 2 |  | ||||||
|             if(User.userRole==SecurityObjects::ROOT) |             if(User.userRole==SecurityObjects::ROOT) | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             //  rule 3 |             if(User.Id == Target.Id) | ||||||
|             if(User.id == Target.id) |  | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             //  rule 4 |             if(User.userRole!=SecurityObjects::ADMIN && User.userRole!=SecurityObjects::ROOT && Op!=READ) | ||||||
|             if(Target.userRole==SecurityObjects::ROOT && Op!=READ) |  | ||||||
|                 return false; |                 return false; | ||||||
|  |  | ||||||
|             if(Op==CREATE) { |             if(Target.userRole==SecurityObjects::ROOT && Op!=READ) | ||||||
|                 if(User.userRole==SecurityObjects::ROOT) |  | ||||||
|                     return true; |  | ||||||
|                 if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN || |  | ||||||
|                     Target.userRole==SecurityObjects::SUBSCRIBER || |  | ||||||
|                     Target.userRole==SecurityObjects::CSR || |  | ||||||
|                     Target.userRole==SecurityObjects::INSTALLER || |  | ||||||
|                     Target.userRole==SecurityObjects::NOC || |  | ||||||
|                     Target.userRole==SecurityObjects::ACCOUNTING)) |  | ||||||
|                     return true; |  | ||||||
|                 if(User.userRole==SecurityObjects::ADMIN && |  | ||||||
|                     (Target.userRole==SecurityObjects::ADMIN || |  | ||||||
|                     Target.userRole==SecurityObjects::SUBSCRIBER || |  | ||||||
|                     Target.userRole==SecurityObjects::CSR || |  | ||||||
|                     Target.userRole==SecurityObjects::INSTALLER || |  | ||||||
|                     Target.userRole==SecurityObjects::NOC || |  | ||||||
|                     Target.userRole==SecurityObjects::ACCOUNTING)) |  | ||||||
|                     return true; |  | ||||||
|                 if(User.userRole==SecurityObjects::ACCOUNTING && |  | ||||||
|                     (Target.userRole==SecurityObjects::SUBSCRIBER || |  | ||||||
|                     Target.userRole==SecurityObjects::INSTALLER || |  | ||||||
|                     Target.userRole==SecurityObjects::CSR)) |  | ||||||
|                     return true; |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								src/APIServers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/APIServers.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-10-23. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | #include "RESTAPI/RESTAPI_oauth2Handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_user_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_users_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_action_links.h" | ||||||
|  | #include "RESTAPI/RESTAPI_systemEndpoints_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_AssetServer.h" | ||||||
|  | #include "RESTAPI/RESTAPI_avatarHandler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_email_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_sms_handler.h" | ||||||
|  | #include "RESTAPI/RESTAPI_validateToken_handler.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, | ||||||
|  |                                                             Poco::Logger & L, RESTAPI_GenericServer & S) { | ||||||
|  |         return RESTAPI_Router< | ||||||
|  |             RESTAPI_oauth2Handler, | ||||||
|  |             RESTAPI_users_handler, | ||||||
|  |             RESTAPI_user_handler, | ||||||
|  |             RESTAPI_system_command, | ||||||
|  |             RESTAPI_AssetServer, | ||||||
|  |             RESTAPI_systemEndpoints_handler, | ||||||
|  |             RESTAPI_action_links, | ||||||
|  |             RESTAPI_avatarHandler, | ||||||
|  |             RESTAPI_email_handler, | ||||||
|  |             RESTAPI_sms_handler | ||||||
|  |         >(Path, Bindings, L, S); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Poco::Net::HTTPRequestHandler * RESTAPI_internal_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, | ||||||
|  |                                                             Poco::Logger & L, RESTAPI_GenericServer & S) { | ||||||
|  |         return RESTAPI_Router_I< | ||||||
|  |             RESTAPI_users_handler, | ||||||
|  |             RESTAPI_user_handler, | ||||||
|  |             RESTAPI_system_command, | ||||||
|  |             RESTAPI_action_links, | ||||||
|  |             RESTAPI_validateToken_handler, | ||||||
|  |             RESTAPI_sms_handler | ||||||
|  |         >(Path, Bindings, L, S); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -32,7 +32,7 @@ namespace OpenWifi { | |||||||
|             std::vector<SecurityObjects::ActionLink>    Links; |             std::vector<SecurityObjects::ActionLink>    Links; | ||||||
|             { |             { | ||||||
|                 std::lock_guard G(Mutex_); |                 std::lock_guard G(Mutex_); | ||||||
|                 StorageService()->ActionLinksDB().GetActions(Links); |                 StorageService()->GetActions(Links); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(Links.empty()) |             if(Links.empty()) | ||||||
| @@ -43,52 +43,23 @@ namespace OpenWifi { | |||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|                 SecurityObjects::UserInfo UInfo; |                 SecurityObjects::UserInfo UInfo; | ||||||
|                 if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD || |                 if(!StorageService()->GetUserById(i.userId,UInfo)) { | ||||||
|                     i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) { |                     StorageService()->CancelAction(i.id); | ||||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); |  | ||||||
|                     continue; |  | ||||||
|                 } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD || |  | ||||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { |  | ||||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); |  | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 switch(i.action) { |                 if(i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD) { | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { |                     if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { |                         Logger_.information(Poco::format("Send password reset link to %s",UInfo.email)); | ||||||
|                                 Logger().information(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, 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: { |  | ||||||
|                             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: { |  | ||||||
|                             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); |  | ||||||
|                         } |  | ||||||
|                         break; |  | ||||||
|  |  | ||||||
|                     default: { |  | ||||||
|                         StorageService()->ActionLinksDB().SentAction(i.id); |  | ||||||
|                     } |                     } | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|  |                 } else if (i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) { | ||||||
|  |                     if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||||
|  |                         Logger_.information(Poco::format("Send email verification link to %s",UInfo.email)); | ||||||
|  |                     } | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|  |                 } else { | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -12,13 +12,11 @@ namespace OpenWifi { | |||||||
|     class ActionLinkManager : public SubSystemServer, Poco::Runnable { |     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
| /*        enum Actions { |         enum Actions { | ||||||
|             FORGOT_PASSWORD, |             FORGOT_PASSWORD, | ||||||
|             VERIFY_EMAIL, |             VERIFY_EMAIL | ||||||
|             SUB_FORGOT_PASSWORD, |  | ||||||
|             SUB_VERIFY_EMAIL |  | ||||||
|         }; |         }; | ||||||
| */ |  | ||||||
|         static ActionLinkManager * instance() { |         static ActionLinkManager * instance() { | ||||||
|             static auto * instance_ = new ActionLinkManager; |             static auto * instance_ = new ActionLinkManager; | ||||||
|             return instance_; |             return instance_; | ||||||
|   | |||||||
| @@ -45,23 +45,15 @@ namespace OpenWifi { | |||||||
|     int AuthService::Start() { |     int AuthService::Start() { | ||||||
| 		Signer_.setRSAKey(MicroService::instance().Key()); | 		Signer_.setRSAKey(MicroService::instance().Key()); | ||||||
| 		Signer_.addAllAlgorithms(); | 		Signer_.addAllAlgorithms(); | ||||||
| 		Logger().notice("Starting..."); | 		Logger_.notice("Starting..."); | ||||||
|  |         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||||
|         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); |         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); | ||||||
|         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); |         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); | ||||||
|  |  | ||||||
|         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); |  | ||||||
|         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); |  | ||||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); |  | ||||||
|  |  | ||||||
|         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; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AuthService::Stop() { |     void AuthService::Stop() { | ||||||
| 		Logger().notice("Stopping..."); | 		Logger_.notice("Stopping..."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||||
| @@ -75,132 +67,84 @@ namespace OpenWifi { | |||||||
| 		        CallToken = Auth.getBearerToken(); | 		        CallToken = Auth.getBearerToken(); | ||||||
| 		    } | 		    } | ||||||
|  |  | ||||||
|             if(CallToken.empty()) { | 		    if(!CallToken.empty()) { | ||||||
|                 return false; | 		        auto Client = UserCache_.get(CallToken); | ||||||
|             } | 		        if( Client.isNull() ) { | ||||||
|  | 		            SecurityObjects::UserInfoAndPolicy UInfo2; | ||||||
|             SecurityObjects::WebToken   WT; | 		            uint64_t RevocationDate=0; | ||||||
|             uint64_t                    RevocationDate=0; | 		            if(StorageService()->GetToken(CallToken,UInfo2,RevocationDate)) { | ||||||
|             std::string                 UserId; | 		                if(RevocationDate!=0) | ||||||
|             if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { | 		                    return false; | ||||||
|                 if(RevocationDate!=0) | 		                Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr); | ||||||
|                     return false; | 		                if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) { | ||||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); | 		                    UInfo.webtoken = UInfo2.webtoken; | ||||||
|                 if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) { | 		                    UserCache_.update(CallToken, UInfo); | ||||||
|                     UInfo.webtoken = WT; | 		                    SessionToken = CallToken; | ||||||
|                     SessionToken = CallToken; | 		                    return true; | ||||||
|                     return true; | 		                } | ||||||
|                 } | 		            } | ||||||
|             } | 		            return false; | ||||||
|             return false; | 		        } | ||||||
|  | 		        if(!Expired) { | ||||||
|  | 		            SessionToken = CallToken; | ||||||
|  | 		            UInfo = *Client ; | ||||||
|  | 		            return true; | ||||||
|  | 		        } | ||||||
|  |                 RevokeToken(CallToken); | ||||||
|  | 		        return false; | ||||||
|  | 		    } | ||||||
| 		} catch(const Poco::Exception &E) { | 		} catch(const Poco::Exception &E) { | ||||||
| 		    Logger().log(E); | 		    Logger_.log(E); | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) |  | ||||||
|     { |  | ||||||
|         std::lock_guard	Guard(Mutex_); |  | ||||||
|         Expired = false; |  | ||||||
|         try { |  | ||||||
|             std::string CallToken; |  | ||||||
|             Poco::Net::OAuth20Credentials Auth(Request); |  | ||||||
|             if (Auth.getScheme() == "Bearer") { |  | ||||||
|                 CallToken = Auth.getBearerToken(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(CallToken.empty()) { |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             SecurityObjects::WebToken   WT; |  | ||||||
|             uint64_t                    RevocationDate=0; |  | ||||||
|             std::string                 UserId; |  | ||||||
|             if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) { |  | ||||||
|                 if(RevocationDate!=0) |  | ||||||
|                     return false; |  | ||||||
|                 Expired = (WT.created_ + WT.expires_in_) < time(nullptr); |  | ||||||
|                 if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) { |  | ||||||
|                     UInfo.webtoken = WT; |  | ||||||
|                     SessionToken = CallToken; |  | ||||||
|                     return true; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } catch(const Poco::Exception &E) { |  | ||||||
|             Logger().log(E); |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AuthService::RevokeToken(std::string & Token) { |     void AuthService::RevokeToken(std::string & Token) { | ||||||
|         StorageService()->UserTokenDB().RevokeToken(Token); |         UserCache_.remove(Token); | ||||||
|  |         StorageService()->RevokeToken(Token); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AuthService::RevokeSubToken(std::string & Token) { |     bool AuthService::DeleteUserFromCache(const std::string &UserName) { | ||||||
|         StorageService()->SubTokenDB().RevokeToken(Token); |         std::lock_guard		Guard(Mutex_); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::DeleteUserFromCache(const std::string &Id) { |         std::vector<std::string>    OldTokens; | ||||||
|         return StorageService()->UserTokenDB().DeleteRecordsFromCache("userName",Id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::DeleteSubUserFromCache(const std::string &Id) { |         UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void | ||||||
|         return StorageService()->SubTokenDB().DeleteRecordsFromCache("userName",Id); |         { if(O.userinfo.email==UserName) | ||||||
|  |             OldTokens.push_back(token); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         for(const auto &i:OldTokens) { | ||||||
|  |             Logout(i,false); | ||||||
|  |             UserCache_.remove(i); | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) { |     bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) { | ||||||
|         return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer::MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method)); |         return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer().MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::ValidatePassword(const std::string &Password) { |     bool AuthService::ValidatePassword(const std::string &Password) { | ||||||
|         return std::regex_match(Password, PasswordValidation_); |         return std::regex_match(Password, PasswordValidation_); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::ValidateSubPassword(const std::string &Password) { |     void AuthService::Logout(const std::string &token, bool EraseFromCache) { | ||||||
|         return std::regex_match(Password, SubPasswordValidation_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AuthService::RemoveTokenSystemWide(const std::string &token) { |  | ||||||
|         try { |  | ||||||
|             if(KafkaManager()->Enabled()) { |  | ||||||
|                 Poco::JSON::Object Obj; |  | ||||||
|                 Obj.set("event", "remove-token"); |  | ||||||
|                 Obj.set("id", MicroService::instance().ID()); |  | ||||||
|                 Obj.set("token", token); |  | ||||||
|                 std::stringstream ResultText; |  | ||||||
|                 Poco::JSON::Stringifier::stringify(Obj, ResultText); |  | ||||||
|                 KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), |  | ||||||
|                                             ResultText.str(), |  | ||||||
|                                             false); |  | ||||||
|             } |  | ||||||
|         } catch (const Poco::Exception &E) { |  | ||||||
|             Logger().log(E); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AuthService::Logout(const std::string &Token, bool EraseFromCache) { |  | ||||||
| 		std::lock_guard		Guard(Mutex_); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             auto tToken{Token}; |             Poco::JSON::Object Obj; | ||||||
|             StorageService()->UserTokenDB().DeleteRecord("token",tToken); |             Obj.set("event", "remove-token"); | ||||||
|             StorageService()->LoginDB().AddLogout(Token); |             Obj.set("id", MicroService::instance().ID()); | ||||||
|  |             Obj.set("token", token); | ||||||
|  |             std::stringstream ResultText; | ||||||
|  |             Poco::JSON::Stringifier::stringify(Obj, ResultText); | ||||||
|  |             std::string Tmp{token}; | ||||||
|  |             RevokeToken(Tmp); | ||||||
|  |             KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), | ||||||
|  |                                         false); | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|             Logger().log(E); |             Logger_.log(E); | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AuthService::SubLogout(const std::string &Token, bool EraseFromCache) { |  | ||||||
|         std::lock_guard		Guard(Mutex_); |  | ||||||
|  |  | ||||||
|         try { |  | ||||||
|             auto tToken{Token}; |  | ||||||
|             StorageService()->SubTokenDB().DeleteRecord("token",tToken); |  | ||||||
|             StorageService()->SubLoginDB().AddLogout(Token); |  | ||||||
|         } catch (const Poco::Exception &E) { |  | ||||||
|             Logger().log(E); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -240,42 +184,18 @@ namespace OpenWifi { | |||||||
|         UInfo.webtoken.expires_in_ = TokenAging_ ; |         UInfo.webtoken.expires_in_ = TokenAging_ ; | ||||||
|         UInfo.webtoken.idle_timeout_ = 5 * 60; |         UInfo.webtoken.idle_timeout_ = 5 * 60; | ||||||
|         UInfo.webtoken.token_type_ = "Bearer"; |         UInfo.webtoken.token_type_ = "Bearer"; | ||||||
|         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); |         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); | ||||||
|         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); |         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); | ||||||
|         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM); |         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,CUSTOM); | ||||||
|         UInfo.webtoken.created_ = time(nullptr); |         UInfo.webtoken.created_ = time(nullptr); | ||||||
|         UInfo.webtoken.username_ = UserName; |         UInfo.webtoken.username_ = UserName; | ||||||
|         UInfo.webtoken.errorCode = 0; |         UInfo.webtoken.errorCode = 0; | ||||||
|         UInfo.webtoken.userMustChangePassword = false; |         UInfo.webtoken.userMustChangePassword = false; | ||||||
|         StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); |         UserCache_.update(UInfo.webtoken.access_token_,UInfo); | ||||||
|         StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_, |         StorageService()->SetLastLogin(UInfo.userinfo.Id); | ||||||
|  |         StorageService()->AddToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_, | ||||||
|                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, |                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, | ||||||
|                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); |                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); | ||||||
|         StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) |  | ||||||
|     { |  | ||||||
|         std::lock_guard		Guard(Mutex_); |  | ||||||
|  |  | ||||||
|         SecurityObjects::AclTemplate	ACL; |  | ||||||
|         ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true; |  | ||||||
|         UInfo.webtoken.acl_template_ = ACL; |  | ||||||
|         UInfo.webtoken.expires_in_ = TokenAging_ ; |  | ||||||
|         UInfo.webtoken.idle_timeout_ = 5 * 60; |  | ||||||
|         UInfo.webtoken.token_type_ = "Bearer"; |  | ||||||
|         UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); |  | ||||||
|         UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME); |  | ||||||
|         UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM); |  | ||||||
|         UInfo.webtoken.created_ = time(nullptr); |  | ||||||
|         UInfo.webtoken.username_ = UserName; |  | ||||||
|         UInfo.webtoken.errorCode = 0; |  | ||||||
|         UInfo.webtoken.userMustChangePassword = false; |  | ||||||
|         StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); |  | ||||||
|         StorageService()->SubTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_, |  | ||||||
|                                    UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, |  | ||||||
|                                    UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); |  | ||||||
|         StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { |     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { | ||||||
| @@ -312,40 +232,6 @@ namespace OpenWifi { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { |  | ||||||
|         std::lock_guard     G(Mutex_); |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UInfo.email); |  | ||||||
|         for (const auto &i:UInfo.lastPasswords) { |  | ||||||
|             auto Tokens = Poco::StringTokenizer(i,"|"); |  | ||||||
|             if(Tokens.count()==2) { |  | ||||||
|                 const auto & Salt = Tokens[0]; |  | ||||||
|                 for(const auto &j:UInfo.lastPasswords) { |  | ||||||
|                     auto OldTokens = Poco::StringTokenizer(j,"|"); |  | ||||||
|                     if(OldTokens.count()==2) { |  | ||||||
|                         SHA2_.update(Salt+NewPassword+UInfo.email); |  | ||||||
|                         if(OldTokens[1]==Utils::ToHex(SHA2_.digest())) |  | ||||||
|                             return false; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 SHA2_.update(NewPassword+UInfo.email); |  | ||||||
|                 if(Tokens[0]==Utils::ToHex(SHA2_.digest())) |  | ||||||
|                     return false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(UInfo.lastPasswords.size()==HowManyOldPassword_) { |  | ||||||
|             UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword); |  | ||||||
|         UInfo.lastPasswords.push_back(NewHash); |  | ||||||
|         UInfo.currentPassword = NewHash; |  | ||||||
|         UInfo.changePassword = false; |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static std::string GetMeSomeSalt() { |     static std::string GetMeSomeSalt() { | ||||||
|         auto start = std::chrono::high_resolution_clock::now(); |         auto start = std::chrono::high_resolution_clock::now(); | ||||||
|         return std::to_string(start.time_since_epoch().count()); |         return std::to_string(start.time_since_epoch().count()); | ||||||
| @@ -375,30 +261,13 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) { |  | ||||||
|         std::lock_guard G(Mutex_); |  | ||||||
|  |  | ||||||
|         std::string UName = Poco::trim(Poco::toLower(UserName)); |  | ||||||
|         auto Tokens = Poco::StringTokenizer(StoredPassword,"|"); |  | ||||||
|         if(Tokens.count()==1) { |  | ||||||
|             SHA2_.update(Password+UName); |  | ||||||
|             if(Tokens[0]==Utils::ToHex(SHA2_.digest())) |  | ||||||
|                 return true; |  | ||||||
|         } else if (Tokens.count()==2) { |  | ||||||
|             SHA2_.update(Tokens[0]+Password+UName); |  | ||||||
|             if(Tokens[1]==Utils::ToHex(SHA2_.digest())) |  | ||||||
|                 return true; |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , 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_); |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UserName); |         Poco::toLowerInPlace(UserName); | ||||||
|  |  | ||||||
|         if(StorageService()->UserDB().GetUserByEmail(UserName,UInfo.userinfo)) { |         if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { | ||||||
|             if(UInfo.userinfo.waitingForEmailCheck) { |             if(UInfo.userinfo.waitingForEmailCheck) { | ||||||
|                 return USERNAME_PENDING_VERIFICATION; |                 return USERNAME_PENDING_VERIFICATION; | ||||||
|             } |             } | ||||||
| @@ -423,13 +292,12 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); |                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); | ||||||
|                 UInfo.userinfo.changePassword = false; |                 UInfo.userinfo.changePassword = false; | ||||||
|                 UInfo.userinfo.modified = std::time(nullptr); |                 StorageService()->UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.Id,UInfo.userinfo); | ||||||
|                 StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             //  so we have a good password, password up date has taken place if need be, now generate the token. |             //  so we have a good password, password up date has taken place if need be, now generate the token. | ||||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); |             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||||
|             StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id); |             StorageService()->SetLastLogin(UInfo.userinfo.Id); | ||||||
|             CreateToken(UserName, UInfo ); |             CreateToken(UserName, UInfo ); | ||||||
|  |  | ||||||
|             return SUCCESS; |             return SUCCESS; | ||||||
| @@ -438,56 +306,10 @@ namespace OpenWifi { | |||||||
|         return INVALID_CREDENTIALS; |         return INVALID_CREDENTIALS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) |  | ||||||
|     { |  | ||||||
|         std::lock_guard		Guard(Mutex_); |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UserName); |  | ||||||
|  |  | ||||||
|         if(StorageService()->SubDB().GetUserByEmail(UserName,UInfo.userinfo)) { |  | ||||||
|             if(UInfo.userinfo.waitingForEmailCheck) { |  | ||||||
|                 return USERNAME_PENDING_VERIFICATION; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(!ValidateSubPasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) { |  | ||||||
|                 return INVALID_CREDENTIALS; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(UInfo.userinfo.changePassword && NewPassword.empty()) { |  | ||||||
|                 UInfo.webtoken.userMustChangePassword = true ; |  | ||||||
|                 return PASSWORD_CHANGE_REQUIRED; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(!NewPassword.empty() && !ValidateSubPassword(NewPassword)) { |  | ||||||
|                 return PASSWORD_INVALID; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if(UInfo.userinfo.changePassword || !NewPassword.empty()) { |  | ||||||
|                 if(!SetSubPassword(NewPassword,UInfo.userinfo)) { |  | ||||||
|                     UInfo.webtoken.errorCode = 1; |  | ||||||
|                     return PASSWORD_ALREADY_USED; |  | ||||||
|                 } |  | ||||||
|                 UInfo.userinfo.lastPasswordChange = std::time(nullptr); |  | ||||||
|                 UInfo.userinfo.changePassword = false; |  | ||||||
|                 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=std::time(nullptr); |  | ||||||
|             StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id); |  | ||||||
|             CreateSubToken(UserName, UInfo ); |  | ||||||
|  |  | ||||||
|             return SUCCESS; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return INVALID_CREDENTIALS; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { |     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { |         if(StorageService()->GetUserByEmail(Email,UInfo)) { | ||||||
|             switch (Reason) { |             switch (Reason) { | ||||||
|  |  | ||||||
|                 case FORGOT_PASSWORD: { |                 case FORGOT_PASSWORD: { | ||||||
| @@ -519,41 +341,6 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     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 FORGOT_PASSWORD: { |  | ||||||
|                     MessageAttributes Attrs; |  | ||||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; |  | ||||||
|                     Attrs[LOGO] = GetLogoAssetURI(); |  | ||||||
|                     Attrs[SUBJECT] = "Password reset link"; |  | ||||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; |  | ||||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|  |  | ||||||
|                 case EMAIL_VERIFICATION: { |  | ||||||
|                     MessageAttributes Attrs; |  | ||||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; |  | ||||||
|                     Attrs[LOGO] = GetLogoAssetURI(); |  | ||||||
|                     Attrs[SUBJECT] = "EMail Address Verification"; |  | ||||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; |  | ||||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |  | ||||||
|                     UInfo.waitingForEmailCheck = true; |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|  |  | ||||||
|                 default: |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { |     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { | ||||||
|         SecurityObjects::ActionLink A; |         SecurityObjects::ActionLink A; | ||||||
|  |  | ||||||
| @@ -562,65 +349,44 @@ namespace OpenWifi { | |||||||
|         A.id = MicroService::CreateUUID(); |         A.id = MicroService::CreateUUID(); | ||||||
|         A.created = std::time(nullptr); |         A.created = std::time(nullptr); | ||||||
|         A.expires = A.created + 24*60*60; |         A.expires = A.created + 24*60*60; | ||||||
|         A.userAction = true; |         StorageService()->CreateAction(A); | ||||||
|         StorageService()->ActionLinksDB().CreateAction(A); |  | ||||||
|         UInfo.waitingForEmailCheck = true; |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::VerifySubEmail(SecurityObjects::UserInfo &UInfo) { |  | ||||||
|         SecurityObjects::ActionLink A; |  | ||||||
|  |  | ||||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL; |  | ||||||
|         A.userId = UInfo.email; |  | ||||||
|         A.id = MicroService::CreateUUID(); |  | ||||||
|         A.created = std::time(nullptr); |  | ||||||
|         A.expires = A.created + 24*60*60; |  | ||||||
|         A.userAction = false; |  | ||||||
|         StorageService()->ActionLinksDB().CreateAction(A); |  | ||||||
|         UInfo.waitingForEmailCheck = true; |         UInfo.waitingForEmailCheck = true; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { |     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { | ||||||
|  |  | ||||||
|         std::lock_guard G(Mutex_); |         std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|         Expired = false; |         Expired = false; | ||||||
|  |  | ||||||
|         std::string TToken{Token}, UserId; |         auto Client = UserCache_.get(Token); | ||||||
|         SecurityObjects::WebToken   WT; |         if(!Client.isNull()) { | ||||||
|         uint64_t RevocationDate=0; |             Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr); | ||||||
|         if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { |             WebToken = Client->webtoken; | ||||||
|             if(RevocationDate!=0) |             UserInfo = Client->userinfo; | ||||||
|                 return false; |             return true; | ||||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); |         } | ||||||
|             if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) { |  | ||||||
|                 WebToken = WT; |         std::string TToken{Token}; | ||||||
|                 return true; |         if(StorageService()->IsTokenRevoked(TToken)) { | ||||||
|             } |  | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         return IsValidSubToken(Token, WebToken, UserInfo, Expired); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { |         //  get the token from disk... | ||||||
|         std::lock_guard G(Mutex_); |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|         Expired = false; |  | ||||||
|  |  | ||||||
|         std::string TToken{Token}, UserId; |  | ||||||
|         SecurityObjects::WebToken   WT; |  | ||||||
|         uint64_t RevocationDate=0; |         uint64_t RevocationDate=0; | ||||||
|         if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) { |         if(StorageService()->GetToken(TToken, UInfo, RevocationDate)) { | ||||||
|             if(RevocationDate!=0) |             if(RevocationDate!=0) | ||||||
|                 return false; |                 return false; | ||||||
|             Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr); |             Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr); | ||||||
|             if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) { |             if(StorageService()->GetUserById(UInfo.userinfo.Id,UInfo.userinfo)) { | ||||||
|                 WebToken = WT; |                 WebToken = UInfo.webtoken; | ||||||
|  |                 UserCache_.update(UInfo.webtoken.access_token_, UInfo); | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| }  // end of namespace | }  // end of namespace | ||||||
|   | |||||||
| @@ -44,8 +44,8 @@ namespace OpenWifi{ | |||||||
|         static ACCESS_TYPE IntToAccessType(int C); |         static ACCESS_TYPE IntToAccessType(int C); | ||||||
|         static int AccessTypeToInt(ACCESS_TYPE T); |         static int AccessTypeToInt(ACCESS_TYPE T); | ||||||
|  |  | ||||||
|         static auto instance() { |         static AuthService *instance() { | ||||||
|             static auto instance_ = new AuthService; |             static auto * instance_ = new AuthService; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -59,44 +59,23 @@ namespace OpenWifi{ | |||||||
|         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; |         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||||
|         void Logout(const std::string &token, bool EraseFromCache=true); |         void Logout(const std::string &token, bool EraseFromCache=true); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); |  | ||||||
|         [[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); |  | ||||||
|         void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); |  | ||||||
|         [[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); |  | ||||||
|         [[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;}; |  | ||||||
|         void SubLogout(const std::string &token, bool EraseFromCache=true); |  | ||||||
|  |  | ||||||
|         void RemoveTokenSystemWide(const std::string &token); |  | ||||||
|  |  | ||||||
|         bool ValidatePassword(const std::string &pwd); |         bool ValidatePassword(const std::string &pwd); | ||||||
|         bool ValidateSubPassword(const std::string &pwd); |  | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); |         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); | ||||||
|         [[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); |  | ||||||
|         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|  |  | ||||||
|         [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); |         [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); | ||||||
|         [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); |         [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); | ||||||
|         [[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); |  | ||||||
|  |  | ||||||
|         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); |         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); | ||||||
|         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); |         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); |  | ||||||
|         [[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName); |  | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); |         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); |  | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); | ||||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); |         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|  |  | ||||||
|         bool DeleteUserFromCache(const std::string &UserName); |  | ||||||
|         bool DeleteSubUserFromCache(const std::string &UserName); |  | ||||||
|         void RevokeToken(std::string & Token); |         void RevokeToken(std::string & Token); | ||||||
|         void RevokeSubToken(std::string & Token); |  | ||||||
|  |  | ||||||
|         [[nodiscard]] static inline const std::string GetLogoAssetURI() { |         [[nodiscard]] static inline const std::string GetLogoAssetURI() { | ||||||
|             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; |             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; | ||||||
| @@ -106,26 +85,14 @@ namespace OpenWifi{ | |||||||
|             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; |             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; } |  | ||||||
|         inline const std::string & GetAccessPolicy() const { return AccessPolicy_; } |  | ||||||
|  |  | ||||||
|         inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; } |  | ||||||
|         inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; } |  | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
| 		Poco::JWT::Signer	Signer_; | 		Poco::JWT::Signer	Signer_; | ||||||
| 		Poco::SHA2Engine	SHA2_; | 		Poco::SHA2Engine	SHA2_; | ||||||
|  | 		Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy>    UserCache_{2048,1200000}; | ||||||
| 		std::string         AccessPolicy_; | 		// SecurityObjects::UserInfoCache UserCache_; | ||||||
| 		std::string         PasswordPolicy_; |         std::string         PasswordValidationStr_; | ||||||
| 		std::string         SubAccessPolicy_; | 		std::regex          PasswordValidation_; | ||||||
| 		std::string         SubPasswordPolicy_; | 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | ||||||
| 		std::string         PasswordValidationStr_; |  | ||||||
|         std::string         SubPasswordValidationStr_; |  | ||||||
|         std::regex          PasswordValidation_; |  | ||||||
|         std::regex          SubPasswordValidation_; |  | ||||||
|  |  | ||||||
|         uint64_t            TokenAging_ = 30 * 24 * 60 * 60; |  | ||||||
|         uint64_t            HowManyOldPassword_=5; |         uint64_t            HowManyOldPassword_=5; | ||||||
|  |  | ||||||
|         class SHA256Engine : public Poco::Crypto::DigestEngine |         class SHA256Engine : public Poco::Crypto::DigestEngine | ||||||
| @@ -152,13 +119,10 @@ namespace OpenWifi{ | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline auto AuthService() { return AuthService::instance(); } |     inline AuthService * AuthService() { return AuthService::instance(); } | ||||||
|  |  | ||||||
|     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) { |     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) { | ||||||
|         if(Sub) |         return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); | ||||||
|             return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired ); |  | ||||||
|         else |  | ||||||
|             return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } // end of namespace | } // end of namespace | ||||||
|   | |||||||
| @@ -31,7 +31,6 @@ | |||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
| #include "ActionLinkManager.h" | #include "ActionLinkManager.h" | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class Daemon *Daemon::instance_ = nullptr; |     class Daemon *Daemon::instance_ = nullptr; | ||||||
| @@ -49,7 +48,6 @@ namespace OpenWifi { | |||||||
|                                            ActionLinkManager(), |                                            ActionLinkManager(), | ||||||
|                                            SMTPMailerService(), |                                            SMTPMailerService(), | ||||||
|                                            RESTAPI_RateLimiter(), |                                            RESTAPI_RateLimiter(), | ||||||
|                                            TotpCache(), |  | ||||||
|                                            AuthService() |                                            AuthService() | ||||||
|                                    }); |                                    }); | ||||||
|         } |         } | ||||||
| @@ -58,6 +56,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void Daemon::initialize() { |     void Daemon::initialize() { | ||||||
|         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); |         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); | ||||||
|  |         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||||
|  |         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void MicroServicePostInitialization() { |     void MicroServicePostInitialization() { | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
| #include "Poco/Crypto/CipherFactory.h" | #include "Poco/Crypto/CipherFactory.h" | ||||||
| #include "Poco/Crypto/Cipher.h" | #include "Poco/Crypto/Cipher.h" | ||||||
|  |  | ||||||
|  | #include "framework/OpenWifiTypes.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| @@ -43,9 +44,13 @@ namespace OpenWifi { | |||||||
|         void initialize(); |         void initialize(); | ||||||
|         static Daemon *instance(); |         static Daemon *instance(); | ||||||
|         inline const std::string & AssetDir() { return AssetDir_; } |         inline const std::string & AssetDir() { return AssetDir_; } | ||||||
|  |         inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; } | ||||||
|  |         inline const std::string & GetAccessPolicy() const { return AccessPolicy_; } | ||||||
|     private: |     private: | ||||||
|         static Daemon 		*instance_; |         static Daemon 		*instance_; | ||||||
|         std::string         AssetDir_; |         std::string         AssetDir_; | ||||||
|  |         std::string         PasswordPolicy_; | ||||||
|  |         std::string         AccessPolicy_; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline Daemon * Daemon() { return Daemon::instance(); } |     inline Daemon * Daemon() { return Daemon::instance(); } | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ | |||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -32,7 +31,6 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         ChallengeStart.set("uuid",uuid); |         ChallengeStart.set("uuid",uuid); | ||||||
|         ChallengeStart.set("created", Created); |         ChallengeStart.set("created", Created); | ||||||
|         ChallengeStart.set("question", "mfa challenge"); |  | ||||||
|         ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method); |         ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method); | ||||||
|  |  | ||||||
|         Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method }; |         Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method }; | ||||||
| @@ -40,18 +38,18 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) { |     bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) { | ||||||
|         if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) { |         if(Method=="sms" && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) { | ||||||
|             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; |             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; | ||||||
|             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); |             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); | ||||||
|         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { |         } | ||||||
|  |  | ||||||
|  |         if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||||
|             MessageAttributes Attrs; |             MessageAttributes Attrs; | ||||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; |             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); |             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||||
|             Attrs[SUBJECT] = "Login validation code"; |             Attrs[SUBJECT] = "Login validation code"; | ||||||
|             Attrs[CHALLENGE_CODE] = Challenge; |             Attrs[CHALLENGE_CODE] = Challenge; | ||||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); |             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); | ||||||
|         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { |  | ||||||
|             return true; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
| @@ -78,12 +76,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         auto answer = ChallengeResponse->get("answer").toString(); |         auto answer = ChallengeResponse->get("answer").toString(); | ||||||
|         std::string Expecting; |         if(Hint->second.Answer!=answer) { | ||||||
|         if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) { |  | ||||||
|             if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) { |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         } else if(Hint->second.Answer!=answer) { |  | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -93,15 +86,12 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAServer::MethodEnabled(const std::string &Method) { |     bool MFAServer::MethodEnabled(const std::string &Method) { | ||||||
|         if(Method==MFAMETHODS::SMS) |         if(Method=="sms") | ||||||
|             return SMSSender()->Enabled(); |             return SMSSender()->Enabled(); | ||||||
|  |  | ||||||
|         if(Method==MFAMETHODS::EMAIL) |         if(Method=="email") | ||||||
|             return SMTPMailerService()->Enabled(); |             return SMTPMailerService()->Enabled(); | ||||||
|  |  | ||||||
|         if(Method==MFAMETHODS::AUTHENTICATOR) |  | ||||||
|             return true; |  | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,17 +10,6 @@ | |||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     namespace MFAMETHODS { |  | ||||||
|         inline const static std::string SMS{"sms"}; |  | ||||||
|         inline const static std::string EMAIL{"email"}; |  | ||||||
|         inline const static std::string AUTHENTICATOR{"authenticator"}; |  | ||||||
|         inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR }; |  | ||||||
|         inline bool Validate(const std::string &M) { |  | ||||||
|             return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     struct MFACacheEntry { |     struct MFACacheEntry { | ||||||
|         SecurityObjects::UserInfoAndPolicy  UInfo; |         SecurityObjects::UserInfoAndPolicy  UInfo; | ||||||
|         std::string                         Answer; |         std::string                         Answer; | ||||||
| @@ -28,15 +17,14 @@ namespace OpenWifi { | |||||||
|         std::string                         Method; |         std::string                         Method; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|     typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache; |     typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache; | ||||||
|  |  | ||||||
|     class MFAServer : public SubSystemServer{ |     class MFAServer : public SubSystemServer{ | ||||||
|     public: |     public: | ||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|         static auto instance() { |         static MFAServer *instance() { | ||||||
|             static auto instance_ = new MFAServer; |             static auto * instance_ = new MFAServer; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -47,9 +35,7 @@ namespace OpenWifi { | |||||||
|         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); |         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||||
|  |  | ||||||
|         static inline std::string MakeChallenge() { |         static inline std::string MakeChallenge() { | ||||||
|             char buf[16]; |             return std::to_string(MicroService::instance().Random(1,999999)); | ||||||
|             std::sprintf(buf,"%06llu",MicroService::instance().Random(1,999999)); |  | ||||||
|             return buf; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
| @@ -62,7 +48,7 @@ namespace OpenWifi { | |||||||
|         void CleanCache(); |         void CleanCache(); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline auto MFAServer() { return MFAServer::instance(); } |     inline MFAServer & MFAServer() { return *MFAServer::instance(); } | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OWSEC_MFASERVER_H | #endif //OWSEC_MFASERVER_H | ||||||
|   | |||||||
| @@ -2,13 +2,13 @@ | |||||||
| // Created by stephane bourque on 2021-07-10.
 | // Created by stephane bourque on 2021-07-10.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_asset_server.h" | #include "RESTAPI_AssetServer.h" | ||||||
| #include "Poco/File.h" | #include "Poco/File.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/RESTAPI_protocol.h" | ||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_asset_server::DoGet() { |     void RESTAPI_AssetServer::DoGet() { | ||||||
|         Poco::File  AssetFile; |         Poco::File  AssetFile; | ||||||
| 
 | 
 | ||||||
|         if(Request->getURI().find("/favicon.ico") != std::string::npos) { |         if(Request->getURI().find("/favicon.ico") != std::string::npos) { | ||||||
| @@ -2,14 +2,15 @@ | |||||||
| // Created by stephane bourque on 2021-07-10.
 | // Created by stephane bourque on 2021-07-10.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_ASSETSERVER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_ASSETSERVER_H | ||||||
| 
 | 
 | ||||||
| #include "../framework/MicroService.h" | #include "../framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_asset_server : public RESTAPIHandler { |     class RESTAPI_AssetServer : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_POST, |                                          {Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| @@ -18,7 +19,6 @@ namespace OpenWifi { | |||||||
|                                           Poco::Net::HTTPRequest::HTTP_DELETE, |                                           Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|                                           TransactionId, |  | ||||||
|                                           Internal, false) {} |                                           Internal, false) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" , |         static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" , | ||||||
|                                                                                          "/favicon.ico"}; }; |                                                                                          "/favicon.ico"}; }; | ||||||
| @@ -32,3 +32,5 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_ASSETSERVER_H
 | ||||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | |||||||
|         auto Id = GetParameter("id",""); |         auto Id = GetParameter("id",""); | ||||||
|  |  | ||||||
|         SecurityObjects::ActionLink Link; |         SecurityObjects::ActionLink Link; | ||||||
|         if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) |         if(!StorageService()->GetActionLink(Id,Link)) | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
| @@ -58,11 +58,11 @@ namespace OpenWifi { | |||||||
|             auto Now = std::time(nullptr); |             auto Now = std::time(nullptr); | ||||||
|  |  | ||||||
|             SecurityObjects::ActionLink Link; |             SecurityObjects::ActionLink Link; | ||||||
|             if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) |             if(!StorageService()->GetActionLink(Id,Link)) | ||||||
|                 return DoReturnA404(); |                 return DoReturnA404(); | ||||||
|  |  | ||||||
|             if(Now > Link.expires) { |             if(Now > Link.expires) { | ||||||
|                 StorageService()->ActionLinksDB().CancelAction(Id); |                 StorageService()->CancelAction(Id); | ||||||
|                 return DoReturnA404(); |                 return DoReturnA404(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -77,9 +77,7 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             SecurityObjects::UserInfo   UInfo; |             SecurityObjects::UserInfo   UInfo; | ||||||
|  |             if(!StorageService()->GetUserById(Link.userId,UInfo)) { | ||||||
|             bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo); |  | ||||||
|             if(!Found) { |  | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; |                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; | ||||||
| @@ -93,25 +91,18 @@ namespace OpenWifi { | |||||||
|                 return SendHTMLFileBack(FormFile,FormVars); |                 return SendHTMLFileBack(FormFile,FormVars); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo); |             if(!AuthService()->SetPassword(Password1,UInfo)) { | ||||||
|             if(!GoodPassword) { |  | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; |                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; | ||||||
|                 return SendHTMLFileBack(FormFile,FormVars); |                 return SendHTMLFileBack(FormFile,FormVars); | ||||||
|             } |             } | ||||||
|  |             StorageService()->UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||||
|             UInfo.modified = std::time(nullptr); |  | ||||||
|             if(Link.userAction) |  | ||||||
|                 StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); |  | ||||||
|             else |  | ||||||
|                 StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo); |  | ||||||
|  |  | ||||||
|             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; |             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; | ||||||
|             Types::StringPairVec    FormVars{ {"UUID", Id}, |             Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                               {"USERNAME", UInfo.email}, |                                               {"USERNAME", UInfo.email}, | ||||||
|                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|             StorageService()->ActionLinksDB().CompleteAction(Id); |             StorageService()->CompleteAction(Id); | ||||||
|             SendHTMLFileBack(FormFile,FormVars); |             SendHTMLFileBack(FormFile,FormVars); | ||||||
|         } else { |         } else { | ||||||
|             DoReturnA404(); |             DoReturnA404(); | ||||||
| @@ -122,13 +113,12 @@ namespace OpenWifi { | |||||||
|         auto Now = std::time(nullptr); |         auto Now = std::time(nullptr); | ||||||
|  |  | ||||||
|         if(Now > Link.expires) { |         if(Now > Link.expires) { | ||||||
|             StorageService()->ActionLinksDB().CancelAction(Link.id); |             StorageService()->CancelAction(Link.id); | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
|         bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo); |         if (!StorageService()->GetUserById(Link.userId, UInfo)) { | ||||||
|         if (!Found) { |  | ||||||
|             Types::StringPairVec FormVars{{"UUID",       Link.id}, |             Types::StringPairVec FormVars{{"UUID",       Link.id}, | ||||||
|                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; |                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; | ||||||
|             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; |             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; | ||||||
| @@ -140,16 +130,12 @@ namespace OpenWifi { | |||||||
|         UInfo.validated = true; |         UInfo.validated = true; | ||||||
|         UInfo.lastEmailCheck = std::time(nullptr); |         UInfo.lastEmailCheck = std::time(nullptr); | ||||||
|         UInfo.validationDate = std::time(nullptr); |         UInfo.validationDate = std::time(nullptr); | ||||||
|         UInfo.modified  = std::time(nullptr); |         StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||||
|         if(Link.userAction) |  | ||||||
|             StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); |  | ||||||
|         else |  | ||||||
|             StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo); |  | ||||||
|         Types::StringPairVec FormVars{{"UUID",     Link.id}, |         Types::StringPairVec FormVars{{"UUID",     Link.id}, | ||||||
|                                       {"USERNAME", UInfo.email}, |                                       {"USERNAME", UInfo.email}, | ||||||
|                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; |         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; | ||||||
|         StorageService()->ActionLinksDB().CompleteAction(Link.id); |         StorageService()->CompleteAction(Link.id); | ||||||
|         SendHTMLFileBack(FormFile, FormVars); |         SendHTMLFileBack(FormFile, FormVars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,21 +2,22 @@ | |||||||
| // Created by stephane bourque on 2021-06-22. | // Created by stephane bourque on 2021-06-22. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_ACTION_LINKS_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_ACTION_LINKS_H | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_action_links : public RESTAPIHandler { |     class RESTAPI_action_links : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|              std::vector<std::string>{ |              std::vector<std::string>{ | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_GET, |                                         Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_POST, |                                         Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                         Server, |                                         Server, | ||||||
|                                         TransactionId, |  | ||||||
|                                         Internal, |                                         Internal, | ||||||
|                                         false, |                                         false, | ||||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} |                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
| @@ -32,3 +33,5 @@ namespace OpenWifi { | |||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_ACTION_LINKS_H | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_avatar_handler.h" | #include "RESTAPI_avatarHandler.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "Poco/Net/HTMLForm.h" | #include "Poco/Net/HTMLForm.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/RESTAPI_protocol.h" | ||||||
| @@ -22,26 +22,33 @@ namespace OpenWifi { | |||||||
|             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); |             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); | ||||||
|         } |         } | ||||||
|         Poco::CountingInputStream InputStream(Stream); |         Poco::CountingInputStream InputStream(Stream); | ||||||
|         Poco::StreamCopier::copyStream(InputStream, OutputStream_); |         std::ofstream OutputStream(TempFile_.path(), std::ofstream::out); | ||||||
|         Length_ = OutputStream_.str().size(); |         Poco::StreamCopier::copyStream(InputStream, OutputStream); | ||||||
|  |         Length_ = InputStream.chars(); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatar_handler::DoPost() { |     void RESTAPI_avatarHandler::DoPost() { | ||||||
|         std::string Id = UserInfo_.userinfo.id; |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
| 
 | 
 | ||||||
|         std::stringstream SS; |         if (Id.empty() || !StorageService()->GetUserById(Id, UInfo)) { | ||||||
|         AvatarPartHandler partHandler(Id, Logger_, SS); |             return NotFound(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //  if there is an avatar, just remove it...
 | ||||||
|  |         StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||||
|  | 
 | ||||||
|  |         Poco::TemporaryFile TmpFile; | ||||||
|  |         AvatarPartHandler partHandler(Id, Logger_, TmpFile); | ||||||
|  | 
 | ||||||
|         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); |         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); | ||||||
|         Poco::JSON::Object Answer; |         Poco::JSON::Object Answer; | ||||||
| 
 |  | ||||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { |         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); |             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); | ||||||
|             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); |             Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); | ||||||
|             StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, |             StorageService()->SetAvatar(UserInfo_.userinfo.email, | ||||||
|                                  Id, SS.str(), partHandler.ContentType(), partHandler.Name()); |                                  Id, TmpFile, partHandler.ContentType(), partHandler.Name()); | ||||||
|             StorageService()->UserDB().SetAvatar(Id,"1"); |  | ||||||
|         } else { |         } else { | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |             Answer.set(RESTAPI::Protocol::AVATARID, Id); | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); |             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); | ||||||
| @@ -50,31 +57,27 @@ namespace OpenWifi { | |||||||
|         ReturnObject(Answer); |         ReturnObject(Answer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatar_handler::DoGet() { |     void RESTAPI_avatarHandler::DoGet() { | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
|         if (Id.empty()) { |         if (Id.empty()) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
| 
 |         Poco::TemporaryFile TempAvatar; | ||||||
|         std::string Type, Name, AvatarContent; |         std::string Type, Name; | ||||||
|         if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { |         if (!StorageService()->GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|         return SendFileContent(AvatarContent, Type, Name); |         SendFile(TempAvatar, Type, Name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_avatar_handler::DoDelete() { |     void RESTAPI_avatarHandler::DoDelete() { | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); | ||||||
| 
 |         if (Id.empty()) { | ||||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { |             return NotFound(); | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |         } | ||||||
|         } |         if (!StorageService()->DeleteAvatar(UserInfo_.userinfo.email, Id)) { | ||||||
| 
 |  | ||||||
|         if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { |  | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         StorageService()->UserDB().SetAvatar(Id,""); |  | ||||||
|         OK(); |         OK(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,7 +1,10 @@ | |||||||
| //
 | //
 | ||||||
| // Created by stephane bourque on 2021-07-15.
 | // Created by stephane bourque on 2021-07-15.
 | ||||||
| //
 | //
 | ||||||
| #pragma once | 
 | ||||||
|  | #ifndef UCENTRALSEC_RESTAPI_AVATARHANDLER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_AVATARHANDLER_H | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| @@ -9,28 +12,28 @@ namespace OpenWifi { | |||||||
| 
 | 
 | ||||||
|     class AvatarPartHandler : public Poco::Net::PartHandler { |     class AvatarPartHandler : public Poco::Net::PartHandler { | ||||||
|     public: |     public: | ||||||
|         AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) : |         AvatarPartHandler(std::string Id, Poco::Logger &Logger, Poco::TemporaryFile &TmpFile) : | ||||||
|                 Id_(std::move(Id)), |                 Id_(std::move(Id)), | ||||||
|                 Logger_(Logger), |                 Logger_(Logger), | ||||||
|                 OutputStream_(ofs){ |                 TempFile_(TmpFile){ | ||||||
|         } |         } | ||||||
|         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); |         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); | ||||||
|         [[nodiscard]] uint64_t Length() const { return Length_; } |         [[nodiscard]] uint64_t Length() const { return Length_; } | ||||||
|         [[nodiscard]] std::string &Name() { return Name_; } |         [[nodiscard]] std::string &Name() { return Name_; } | ||||||
|         [[nodiscard]] std::string &ContentType() { return FileType_; } |         [[nodiscard]] std::string &ContentType() { return FileType_; } | ||||||
| 
 |         [[nodiscard]] std::string FileName() const { return TempFile_.path(); } | ||||||
|     private: |     private: | ||||||
|         uint64_t        Length_ = 0; |         uint64_t        Length_ = 0; | ||||||
|         std::string     FileType_; |         std::string     FileType_; | ||||||
|         std::string     Name_; |         std::string     Name_; | ||||||
|         std::string     Id_; |         std::string     Id_; | ||||||
|         Poco::Logger    &Logger_; |         Poco::Logger    &Logger_; | ||||||
|         std::stringstream &OutputStream_; |         Poco::TemporaryFile &TempFile_; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class RESTAPI_avatar_handler : public RESTAPIHandler { |     class RESTAPI_avatarHandler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string>{ |                                  std::vector<std::string>{ | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_GET, |                                          Poco::Net::HTTPRequest::HTTP_GET, | ||||||
| @@ -38,7 +41,6 @@ namespace OpenWifi { | |||||||
|                                          Poco::Net::HTTPRequest::HTTP_DELETE, |                                          Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                          Server, |                                          Server, | ||||||
|                                          TransactionId, |  | ||||||
|                                          Internal) {} |                                          Internal) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/avatar/{id}"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/avatar/{id}"}; }; | ||||||
| 
 | 
 | ||||||
| @@ -49,3 +51,4 @@ namespace OpenWifi { | |||||||
| 
 | 
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_AVATARHANDLER_H
 | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-01. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/orm.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     inline void Sanitize(const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) { |  | ||||||
|         U.currentPassword.clear(); |  | ||||||
|         U.lastPasswords.clear(); |  | ||||||
|         U.oauthType.clear(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -2,19 +2,20 @@ | |||||||
| // Created by stephane bourque on 2021-09-02. | // Created by stephane bourque on 2021-09-02. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef OWSEC_RESTAPI_EMAIL_HANDLER_H | ||||||
|  | #define OWSEC_RESTAPI_EMAIL_HANDLER_H | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_email_handler : public RESTAPIHandler { |     class RESTAPI_email_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|         : RESTAPIHandler(bindings, L, |         : RESTAPIHandler(bindings, L, | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, |                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                   Server, |                                                   Server, | ||||||
|                                                   TransactionId, |  | ||||||
|                                                   Internal) {} |                                                   Internal) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};} |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};} | ||||||
|         void DoGet() final {}; |         void DoGet() final {}; | ||||||
| @@ -23,3 +24,5 @@ namespace OpenWifi { | |||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //OWSEC_RESTAPI_EMAIL_HANDLER_H | ||||||
|   | |||||||
| @@ -8,41 +8,47 @@ | |||||||
| 
 | 
 | ||||||
| #include "Poco/JSON/Parser.h" | #include "Poco/JSON/Parser.h" | ||||||
| 
 | 
 | ||||||
|  | #include "Daemon.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| #include "RESTAPI_oauth2_handler.h" | #include "RESTAPI_oauth2Handler.h" | ||||||
| #include "MFAServer.h" | #include "MFAServer.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/RESTAPI_protocol.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "RESTAPI_db_helpers.h" |  | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| 
 | 
 | ||||||
| 	void RESTAPI_oauth2_handler::DoGet() { |     static void FilterCredentials(SecurityObjects::UserInfo & U) { | ||||||
| 	    bool Expired = false, Contacted = false; |         U.currentPassword.clear(); | ||||||
|         if (!IsAuthorized(Expired, Contacted)) { |         U.lastPasswords.clear(); | ||||||
|  |         U.oauthType.clear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 	void RESTAPI_oauth2Handler::DoGet() { | ||||||
|  | 	    bool Expired = false; | ||||||
|  |         if (!IsAuthorized(Expired)) { | ||||||
|             if(Expired) |             if(Expired) | ||||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); |                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); |             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); | ||||||
|         } |         } | ||||||
|         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); |         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||||
|         if(GetMe) { |         if(GetMe) { | ||||||
|             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); |             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||||
|             Poco::JSON::Object Me; |             Poco::JSON::Object Me; | ||||||
|             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; |             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; | ||||||
|             Sanitize(UserInfo_, ReturnedUser); |             FilterCredentials(ReturnedUser); | ||||||
|             ReturnedUser.to_json(Me); |             ReturnedUser.to_json(Me); | ||||||
|             return ReturnObject(Me); |             return ReturnObject(Me); | ||||||
|         } |         } | ||||||
|         BadRequest(RESTAPI::Errors::UnrecognizedRequest); |         BadRequest(RESTAPI::Errors::UnrecognizedRequest); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_oauth2_handler::DoDelete() { |     void RESTAPI_oauth2Handler::DoDelete() { | ||||||
| 	    bool Expired = false, Contacted=false; | 	    bool Expired = false; | ||||||
| 	    if (!IsAuthorized(Expired, Contacted)) { | 	    if (!IsAuthorized(Expired)) { | ||||||
| 	        if(Expired) | 	        if(Expired) | ||||||
| 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||||
| 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); | 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); | ||||||
| 	    } | 	    } | ||||||
| 
 | 
 | ||||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); |         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||||
| @@ -55,7 +61,7 @@ namespace OpenWifi { | |||||||
|         NotFound(); |         NotFound(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RESTAPI_oauth2_handler::DoPost() { | 	void RESTAPI_oauth2Handler::DoPost() { | ||||||
|         auto Obj = ParseStream(); |         auto Obj = ParseStream(); | ||||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); |         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); | ||||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); |         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); | ||||||
| @@ -67,25 +73,24 @@ namespace OpenWifi { | |||||||
|             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); |             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression()); |             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression()); | ||||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy()); |             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, Daemon()->GetAccessPolicy()); | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy()); |             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, Daemon()->GetPasswordPolicy()); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||||
|             SecurityObjects::UserInfo UInfo1; |             SecurityObjects::UserInfo UInfo1; | ||||||
|             auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1); |             auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1); | ||||||
|             if(UserExists) { |             if(UserExists) { | ||||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); |                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|                 SecurityObjects::ActionLink NewLink; |                 SecurityObjects::ActionLink NewLink; | ||||||
| 
 | 
 | ||||||
|                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; |                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; | ||||||
|                 NewLink.id = MicroService::CreateUUID(); |                 NewLink.id = MicroService::CreateUUID(); | ||||||
|                 NewLink.userId = UInfo1.id; |                 NewLink.userId = UInfo1.Id; | ||||||
|                 NewLink.created = std::time(nullptr); |                 NewLink.created = std::time(nullptr); | ||||||
|                 NewLink.expires = NewLink.created + (24*60*60); |                 NewLink.expires = NewLink.created + (24*60*60); | ||||||
|                 NewLink.userAction = true; |                 StorageService()->CreateAction(NewLink); | ||||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); |  | ||||||
| 
 | 
 | ||||||
|                 Poco::JSON::Object ReturnObj; |                 Poco::JSON::Object ReturnObj; | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
| @@ -105,23 +110,23 @@ namespace OpenWifi { | |||||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); |             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|             if(Obj->has("uuid")) { |             if(Obj->has("uuid")) { | ||||||
|                 auto uuid = Obj->get("uuid").toString(); |                 auto uuid = Obj->get("uuid").toString(); | ||||||
|                 if(MFAServer()->ResendCode(uuid)) |                 if(MFAServer().ResendCode(uuid)) | ||||||
|                     return OK(); |                     return OK(); | ||||||
|             } |             } | ||||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); |             return UnAuthorized(RESTAPI::Errors::InvalidCredentials); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); |             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|             if(Obj->has("uuid")) { |             if(Obj->has("uuid")) { | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|                 if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) { |                 if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) { | ||||||
|                     Poco::JSON::Object ReturnObj; |                     Poco::JSON::Object ReturnObj; | ||||||
|                     UInfo.webtoken.to_json(ReturnObj); |                     UInfo.webtoken.to_json(ReturnObj); | ||||||
|                     return ReturnObject(ReturnObj); |                     return ReturnObject(ReturnObj); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); |             return UnAuthorized(RESTAPI::Errors::InvalidCredentials); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
| @@ -130,7 +135,7 @@ namespace OpenWifi { | |||||||
|         if (Code==SUCCESS) { |         if (Code==SUCCESS) { | ||||||
|             Poco::JSON::Object ReturnObj; |             Poco::JSON::Object ReturnObj; | ||||||
|             if(AuthService()->RequiresMFA(UInfo)) { |             if(AuthService()->RequiresMFA(UInfo)) { | ||||||
|                 if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) { |                 if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { | ||||||
|                     return ReturnObject(ReturnObj); |                     return ReturnObject(ReturnObj); | ||||||
|                 } |                 } | ||||||
|                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); |                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); | ||||||
| @@ -6,20 +6,21 @@ | |||||||
| //	Arilia Wireless Inc.
 | //	Arilia Wireless Inc.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #ifndef UCENTRAL_RESTAPI_OAUTH2HANDLER_H | ||||||
|  | #define UCENTRAL_RESTAPI_OAUTH2HANDLER_H | ||||||
|  | 
 | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| 	class RESTAPI_oauth2_handler : public RESTAPIHandler { | 	class RESTAPI_oauth2Handler : public RESTAPIHandler { | ||||||
| 	  public: | 	  public: | ||||||
| 	    RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | 	    RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
| 			: RESTAPIHandler(bindings, L, | 			: RESTAPIHandler(bindings, L, | ||||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                                       Poco::Net::HTTPRequest::HTTP_GET, |                                                       Poco::Net::HTTPRequest::HTTP_GET, | ||||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
| 													  Server, | 													  Server, | ||||||
|                                                       TransactionId, |  | ||||||
| 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
| 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||||
| 		void DoGet() final; | 		void DoGet() final; | ||||||
| @@ -28,5 +29,4 @@ namespace OpenWifi { | |||||||
| 		void DoPut() final {}; | 		void DoPut() final {}; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| 
 | #endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
 | ||||||
| 
 |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-16. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_preferences.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_preferences::DoGet() { |  | ||||||
|         SecurityObjects::Preferences    P; |  | ||||||
|         Poco::JSON::Object  Answer; |  | ||||||
|         StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P); |  | ||||||
|         P.to_json(Answer); |  | ||||||
|         ReturnObject(Answer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_preferences::DoPut() { |  | ||||||
|  |  | ||||||
|         SecurityObjects::Preferences    P; |  | ||||||
|  |  | ||||||
|         auto RawObject = ParseStream(); |  | ||||||
|         if(!P.from_json(RawObject)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         P.id = UserInfo_.userinfo.id; |  | ||||||
|         P.modified = std::time(nullptr); |  | ||||||
|         StorageService()->PreferencesDB().SetPreferences(P); |  | ||||||
|  |  | ||||||
|         Poco::JSON::Object  Answer; |  | ||||||
|         P.to_json(Answer); |  | ||||||
|         ReturnObject(Answer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-16. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_preferences : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string>{ |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|             Server, |  | ||||||
|             TransactionId, |  | ||||||
|             Internal) {} |  | ||||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/preferences"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPut() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-23. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| #include "RESTAPI/RESTAPI_oauth2_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_user_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_users_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_action_links.h" |  | ||||||
| #include "RESTAPI/RESTAPI_system_endpoints_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_asset_server.h" |  | ||||||
| #include "RESTAPI/RESTAPI_avatar_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_subavatar_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_email_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_sms_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_validate_token_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_preferences.h" |  | ||||||
| #include "RESTAPI/RESTAPI_subpreferences.h" |  | ||||||
| #include "RESTAPI/RESTAPI_suboauth2_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_subuser_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_subusers_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_validate_sub_token_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_submfa_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_totp_handler.h" |  | ||||||
| #include "RESTAPI/RESTAPI_subtotp_handler.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     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_users_handler, |  | ||||||
|             RESTAPI_user_handler, |  | ||||||
|             RESTAPI_system_command, |  | ||||||
|             RESTAPI_asset_server, |  | ||||||
|             RESTAPI_system_endpoints_handler, |  | ||||||
|             RESTAPI_action_links, |  | ||||||
|             RESTAPI_avatar_handler, |  | ||||||
|             RESTAPI_subavatar_handler, |  | ||||||
|             RESTAPI_email_handler, |  | ||||||
|             RESTAPI_sms_handler, |  | ||||||
|             RESTAPI_preferences, |  | ||||||
|             RESTAPI_subpreferences, |  | ||||||
|             RESTAPI_suboauth2_handler, |  | ||||||
|             RESTAPI_subuser_handler, |  | ||||||
|             RESTAPI_subusers_handler, |  | ||||||
|             RESTAPI_submfa_handler, |  | ||||||
|             RESTAPI_totp_handler, |  | ||||||
|             RESTAPI_subtotp_handler |  | ||||||
|         >(Path, Bindings, L, S,TransactionId); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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_users_handler, |  | ||||||
|             RESTAPI_user_handler, |  | ||||||
|             RESTAPI_subuser_handler, |  | ||||||
|             RESTAPI_subusers_handler, |  | ||||||
|             RESTAPI_system_command, |  | ||||||
|             RESTAPI_action_links, |  | ||||||
|             RESTAPI_validate_token_handler, |  | ||||||
|             RESTAPI_validate_sub_token_handler, |  | ||||||
|             RESTAPI_sms_handler, |  | ||||||
|             RESTAPI_preferences, |  | ||||||
|             RESTAPI_subpreferences, |  | ||||||
|             RESTAPI_suboauth2_handler, |  | ||||||
|             RESTAPI_submfa_handler |  | ||||||
|         >(Path, Bindings, L, S, TransactionId); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) { |             if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) { | ||||||
|                 return OK(); |                 return OK(); | ||||||
|             } |             } | ||||||
|             return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry); |             return BadRequest("SMS could not be sent to validate device, try later or change the phone number."); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::string Code; |         std::string Code; | ||||||
| @@ -30,13 +30,7 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) { |             if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) { | ||||||
|                 return OK(); |                 return OK(); | ||||||
|             } |             } | ||||||
|             return BadRequest(RESTAPI::Errors::SMSCouldNotValidate); |             return BadRequest("Code and number could not be validated"); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && |  | ||||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER && |  | ||||||
|             UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights,ACCESS_DENIED); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (Obj->has("to") && |         if (Obj->has("to") && | ||||||
| @@ -47,7 +41,7 @@ namespace OpenWifi { | |||||||
|             if(SMSSender()->Send(PhoneNumber, Text)) |             if(SMSSender()->Send(PhoneNumber, Text)) | ||||||
|                 return OK(); |                 return OK(); | ||||||
|  |  | ||||||
|             return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry); |             return InternalError("SMS Message could not be sent."); | ||||||
|         } |         } | ||||||
|         BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); |         BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,19 +2,20 @@ | |||||||
| // Created by stephane bourque on 2021-10-09. | // Created by stephane bourque on 2021-10-09. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef OWSEC_RESTAPI_SMS_HANDLER_H | ||||||
|  | #define OWSEC_RESTAPI_SMS_HANDLER_H | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_sms_handler : public RESTAPIHandler { |     class RESTAPI_sms_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|         : RESTAPIHandler(bindings, L, |         : RESTAPIHandler(bindings, L, | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, |                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                   Server, |                                                   Server, | ||||||
|                                                   TransactionId, |  | ||||||
|                                                   Internal) {} |                                                   Internal) {} | ||||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};} |                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};} | ||||||
|         void DoGet() final {}; |         void DoGet() final {}; | ||||||
| @@ -23,3 +24,5 @@ namespace OpenWifi { | |||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //OWSEC_RESTAPI_SMS_HANDLER_H | ||||||
|   | |||||||
| @@ -1,79 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-07-15. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include <fstream> |  | ||||||
| #include <iostream> |  | ||||||
|  |  | ||||||
| #include "RESTAPI_subavatar_handler.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
| #include "Poco/Net/HTMLForm.h" |  | ||||||
| #include "framework/RESTAPI_protocol.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) { |  | ||||||
|         FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED); |  | ||||||
|         if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) { |  | ||||||
|             std::string Disposition; |  | ||||||
|             Poco::Net::NameValueCollection Parameters; |  | ||||||
|             Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters); |  | ||||||
|             Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED); |  | ||||||
|         } |  | ||||||
|         Poco::CountingInputStream InputStream(Stream); |  | ||||||
|         Poco::StreamCopier::copyStream(InputStream, OutputStream_); |  | ||||||
|         Length_ = OutputStream_.str().size(); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     void RESTAPI_subavatar_handler::DoPost() { |  | ||||||
|         std::string Id = UserInfo_.userinfo.id; |  | ||||||
|         SecurityObjects::UserInfo UInfo; |  | ||||||
|  |  | ||||||
|         std::stringstream SS; |  | ||||||
|         SubAvatarPartHandler partHandler(Id, Logger_, SS); |  | ||||||
|         Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler); |  | ||||||
|         Poco::JSON::Object Answer; |  | ||||||
|  |  | ||||||
|         if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) { |  | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |  | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 0); |  | ||||||
|             Logger_.information(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"); |  | ||||||
|         } else { |  | ||||||
|             Answer.set(RESTAPI::Protocol::AVATARID, Id); |  | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORCODE, 13); |  | ||||||
|             Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete."); |  | ||||||
|         } |  | ||||||
|         ReturnObject(Answer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subavatar_handler::DoGet() { |  | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |  | ||||||
|         if (Id.empty()) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         std::string Type, Name, AvatarContent; |  | ||||||
|         if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|         return SendFileContent(AvatarContent, Type, Name); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subavatar_handler::DoDelete() { |  | ||||||
|         std::string Id = GetBinding(RESTAPI::Protocol::ID, ""); |  | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|         StorageService()->SubDB().SetAvatar(Id,""); |  | ||||||
|         OK(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-07-15. |  | ||||||
| // |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     class SubAvatarPartHandler : public Poco::Net::PartHandler { |  | ||||||
|     public: |  | ||||||
|         SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) : |  | ||||||
|                 Id_(std::move(Id)), |  | ||||||
|                 Logger_(Logger), |  | ||||||
|                 OutputStream_(ofs){ |  | ||||||
|         } |  | ||||||
|         void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream); |  | ||||||
|         [[nodiscard]] uint64_t Length() const { return Length_; } |  | ||||||
|         [[nodiscard]] std::string &Name() { return Name_; } |  | ||||||
|         [[nodiscard]] std::string &ContentType() { return FileType_; } |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|         uint64_t        Length_ = 0; |  | ||||||
|         std::string     FileType_; |  | ||||||
|         std::string     Name_; |  | ||||||
|         std::string     Id_; |  | ||||||
|         Poco::Logger    &Logger_; |  | ||||||
|         std::stringstream &OutputStream_; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class RESTAPI_subavatar_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|                 : RESTAPIHandler(bindings, L, |  | ||||||
|                                  std::vector<std::string>{ |  | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_POST, |  | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_DELETE, |  | ||||||
|                                          Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                                          Server, |  | ||||||
|                                          TransactionId, |  | ||||||
|                                          Internal) {} |  | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subavatar/{id}"}; }; |  | ||||||
|  |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final; |  | ||||||
|         void DoDelete() final; |  | ||||||
|         void DoPut() final {}; |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,129 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-12-01. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_submfa_handler.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
| #include "SMSSender.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_submfa_handler::DoGet() { |  | ||||||
|         SecurityObjects::UserInfo   User; |  | ||||||
|  |  | ||||||
|         // 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; |  | ||||||
|  |  | ||||||
|             MFC.id = User.id; |  | ||||||
|             if(User.userTypeProprietaryInfo.mfa.enabled) { |  | ||||||
|                 if(User.userTypeProprietaryInfo.mfa.method == "sms") { |  | ||||||
|                     MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number; |  | ||||||
|                     MFC.type = "sms"; |  | ||||||
|                 } else if(User.userTypeProprietaryInfo.mfa.method == "email") { |  | ||||||
|                     MFC.email = User.email; |  | ||||||
|                     MFC.type = "email"; |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 MFC.type = "disabled"; |  | ||||||
|             } |  | ||||||
|             MFC.to_json(Answer); |  | ||||||
|             return ReturnObject(Answer); |  | ||||||
|         } |  | ||||||
|         NotFound(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_submfa_handler::DoPut() { |  | ||||||
|  |  | ||||||
|         try { |  | ||||||
|             auto Body = ParseStream(); |  | ||||||
|  |  | ||||||
|             SecurityObjects::SubMfaConfig MFC; |  | ||||||
|  |  | ||||||
|             if (!MFC.from_json(Body)) { |  | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (MFC.type == "disabled") { |  | ||||||
|                 SecurityObjects::UserInfo User; |  | ||||||
|                 StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); |  | ||||||
|                 User.userTypeProprietaryInfo.mfa.enabled = false; |  | ||||||
|                 StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); |  | ||||||
|  |  | ||||||
|                 Poco::JSON::Object Answer; |  | ||||||
|                 MFC.to_json(Answer); |  | ||||||
|                 return ReturnObject(Answer); |  | ||||||
|             } else if (MFC.type == "email") { |  | ||||||
|                 SecurityObjects::UserInfo User; |  | ||||||
|  |  | ||||||
|                 StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); |  | ||||||
|                 User.userTypeProprietaryInfo.mfa.enabled = true; |  | ||||||
|                 User.userTypeProprietaryInfo.mfa.method = "email"; |  | ||||||
|                 StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); |  | ||||||
|  |  | ||||||
|                 MFC.sms = MFC.sms; |  | ||||||
|                 MFC.type = "email"; |  | ||||||
|                 MFC.email = UserInfo_.userinfo.email; |  | ||||||
|                 MFC.id = MicroService::instance().CreateUUID(); |  | ||||||
|  |  | ||||||
|                 Poco::JSON::Object Answer; |  | ||||||
|                 MFC.to_json(Answer); |  | ||||||
|                 return ReturnObject(Answer); |  | ||||||
|  |  | ||||||
|             } else if (MFC.type == "sms") { |  | ||||||
|                 if (GetBoolParameter("startValidation", false)) { |  | ||||||
|                     if (MFC.sms.empty()) { |  | ||||||
|                         return BadRequest("Missing phone number"); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) { |  | ||||||
|                         return OK(); |  | ||||||
|                     } else { |  | ||||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); |  | ||||||
|                     } |  | ||||||
|                 } else if (GetBoolParameter("completeValidation", false)) { |  | ||||||
|                     auto ChallengeCode = GetParameter("challengeCode", ""); |  | ||||||
|                     if (ChallengeCode.empty()) { |  | ||||||
|                         return BadRequest("Missing 'challengeCode'"); |  | ||||||
|                     } |  | ||||||
|                     if (MFC.sms.empty()) { |  | ||||||
|                         return BadRequest("Missing phone number"); |  | ||||||
|                     } |  | ||||||
|                     if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) { |  | ||||||
|                         SecurityObjects::UserInfo User; |  | ||||||
|  |  | ||||||
|                         StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User); |  | ||||||
|                         User.userTypeProprietaryInfo.mfa.enabled = true; |  | ||||||
|                         User.userTypeProprietaryInfo.mfa.method = "sms"; |  | ||||||
|                         SecurityObjects::MobilePhoneNumber PhoneNumber; |  | ||||||
|                         PhoneNumber.number = MFC.sms; |  | ||||||
|                         PhoneNumber.primary = true; |  | ||||||
|                         PhoneNumber.verified = true; |  | ||||||
|                         User.userTypeProprietaryInfo.mobiles.clear(); |  | ||||||
|                         User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber); |  | ||||||
|  |  | ||||||
|                         StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User); |  | ||||||
|  |  | ||||||
|                         MFC.sms = MFC.sms; |  | ||||||
|                         MFC.type = "sms"; |  | ||||||
|                         MFC.email = UserInfo_.userinfo.email; |  | ||||||
|                         MFC.id = MicroService::instance().CreateUUID(); |  | ||||||
|  |  | ||||||
|                         Poco::JSON::Object Answer; |  | ||||||
|                         MFC.to_json(Answer); |  | ||||||
|  |  | ||||||
|                         return ReturnObject(Answer); |  | ||||||
|  |  | ||||||
|                     } else { |  | ||||||
|                         return InternalError("SMS could not be sent. Verify the number or try again later."); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch (const Poco::Exception &E) { |  | ||||||
|             Logger_.log(E); |  | ||||||
|         } |  | ||||||
|         return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-12-01. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_submfa_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                                                   Server, |  | ||||||
|                                                   TransactionId, |  | ||||||
|                                                   Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10}, |  | ||||||
|                                                   true) {} |  | ||||||
|                                                   static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/submfa"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|         void DoPut() final ; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,153 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #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" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_suboauth2_handler::DoGet() { |  | ||||||
|         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); |  | ||||||
|         } |  | ||||||
|         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); |  | ||||||
|             ReturnedUser.to_json(Me); |  | ||||||
|             return ReturnObject(Me); |  | ||||||
|         } |  | ||||||
|         BadRequest(RESTAPI::Errors::UnrecognizedRequest); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_suboauth2_handler::DoDelete() { |  | ||||||
|         bool Expired = false, Contacted = false; |  | ||||||
|         if (!IsAuthorized(Expired, Contacted, true)) { |  | ||||||
|             if(Expired) |  | ||||||
|                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); |  | ||||||
|         if (Token == SessionToken_) { |  | ||||||
|             AuthService()->SubLogout(Token); |  | ||||||
|             return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); |  | ||||||
|         NotFound(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_suboauth2_handler::DoPost() { |  | ||||||
|         auto Obj = ParseStream(); |  | ||||||
|         auto userId = GetS(RESTAPI::Protocol::USERID, Obj); |  | ||||||
|         auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj); |  | ||||||
|         auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj); |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(userId); |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) { |  | ||||||
|             Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString())); |  | ||||||
|             Poco::JSON::Object  Answer; |  | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression()); |  | ||||||
|             Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy()); |  | ||||||
|             Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy()); |  | ||||||
|             return ReturnObject(Answer); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { |  | ||||||
|             SecurityObjects::UserInfo UInfo1; |  | ||||||
|             auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1); |  | ||||||
|             if(UserExists) { |  | ||||||
|                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); |  | ||||||
|                 SecurityObjects::ActionLink NewLink; |  | ||||||
|  |  | ||||||
|                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD; |  | ||||||
|                 NewLink.id = MicroService::CreateUUID(); |  | ||||||
|                 NewLink.userId = UInfo1.id; |  | ||||||
|                 NewLink.created = std::time(nullptr); |  | ||||||
|                 NewLink.expires = NewLink.created + (24*60*60); |  | ||||||
|                 NewLink.userAction = false; |  | ||||||
|                 StorageService()->ActionLinksDB().CreateAction(NewLink); |  | ||||||
|  |  | ||||||
|                 Poco::JSON::Object ReturnObj; |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 UInfo.webtoken.userMustChangePassword = true; |  | ||||||
|                 UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                 return ReturnObject(ReturnObj); |  | ||||||
|             } else { |  | ||||||
|                 Poco::JSON::Object ReturnObj; |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 UInfo.webtoken.userMustChangePassword = true; |  | ||||||
|                 UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                 return ReturnObject(ReturnObj); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { |  | ||||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); |  | ||||||
|             if(Obj->has("uuid")) { |  | ||||||
|                 auto uuid = Obj->get("uuid").toString(); |  | ||||||
|                 if(MFAServer()->ResendCode(uuid)) |  | ||||||
|                     return OK(); |  | ||||||
|             } |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, BAD_MFA_TRANSACTION); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { |  | ||||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); |  | ||||||
|             if(Obj->has("uuid") && Obj->has("answer")) { |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|                 if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) { |  | ||||||
|                     Poco::JSON::Object ReturnObj; |  | ||||||
|                     UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|                     return ReturnObject(ReturnObj); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InvalidCredentials, MFA_FAILURE); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |  | ||||||
|         bool Expired=false; |  | ||||||
|         auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired); |  | ||||||
|         if (Code==SUCCESS) { |  | ||||||
|             Poco::JSON::Object ReturnObj; |  | ||||||
|             if(AuthService()->RequiresMFA(UInfo)) { |  | ||||||
|                 if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) { |  | ||||||
|                     return ReturnObject(ReturnObj); |  | ||||||
|                 } |  | ||||||
|                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); |  | ||||||
|             } |  | ||||||
|             UInfo.webtoken.to_json(ReturnObj); |  | ||||||
|             return ReturnObject(ReturnObj); |  | ||||||
|         } else { |  | ||||||
|             switch(Code) { |  | ||||||
|                 case INVALID_CREDENTIALS: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); |  | ||||||
|                 case PASSWORD_INVALID: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); |  | ||||||
|                 case PASSWORD_ALREADY_USED: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); |  | ||||||
|                 case USERNAME_PENDING_VERIFICATION: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); |  | ||||||
|                 case PASSWORD_CHANGE_REQUIRED: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); |  | ||||||
|                 default: |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; |  | ||||||
|             } |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_suboauth2_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST, |  | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_DELETE, |  | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                                                   Server, |  | ||||||
|                                                   TransactionId, |  | ||||||
|                                                   Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10}, |  | ||||||
|                                                   false) {} |  | ||||||
|                                                   static 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; |  | ||||||
|         void DoPut() final {}; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-16. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_subpreferences.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_subpreferences::DoGet() { |  | ||||||
|         SecurityObjects::Preferences    P; |  | ||||||
|         Poco::JSON::Object  Answer; |  | ||||||
|         StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P); |  | ||||||
|         P.to_json(Answer); |  | ||||||
|         ReturnObject(Answer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subpreferences::DoPut() { |  | ||||||
|  |  | ||||||
|         SecurityObjects::Preferences    P; |  | ||||||
|  |  | ||||||
|         auto RawObject = ParseStream(); |  | ||||||
|         if(!P.from_json(RawObject)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         P.id = UserInfo_.userinfo.id; |  | ||||||
|         P.modified = std::time(nullptr); |  | ||||||
|         StorageService()->SubPreferencesDB().SetPreferences(P); |  | ||||||
|  |  | ||||||
|         Poco::JSON::Object  Answer; |  | ||||||
|         P.to_json(Answer); |  | ||||||
|         ReturnObject(Answer); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-16. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_subpreferences : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string>{ |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|             Server, |  | ||||||
|             TransactionId, |  | ||||||
|             Internal) {} |  | ||||||
|             static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subpreferences"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPut() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-31. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_subtotp_handler.h" |  | ||||||
|  |  | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_subtotp_handler::DoGet() { |  | ||||||
|  |  | ||||||
|         auto Reset = GetBoolParameter("reset",false); |  | ||||||
|         std::string QRCode; |  | ||||||
|  |  | ||||||
|         if(TotpCache()->StartValidation(UserInfo_.userinfo,true,QRCode,Reset)) { |  | ||||||
|             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); |  | ||||||
|         } |  | ||||||
|         return BadRequest(RESTAPI::Errors::InvalidCommand); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subtotp_handler::DoPut() { |  | ||||||
|         auto Value = GetParameter("value",""); |  | ||||||
|         auto nextIndex = GetParameter("index",0); |  | ||||||
|         bool moreCodes=false; |  | ||||||
|  |  | ||||||
|         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(ErrorCode, ErrorText); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,29 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-31. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_subtotp_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|                 : RESTAPIHandler(bindings, L, |  | ||||||
|                                  std::vector<std::string> |  | ||||||
|                                          { |  | ||||||
|                                                  Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                                                  Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS |  | ||||||
|                                          }, |  | ||||||
|                                  Server, |  | ||||||
|                                  TransactionId, |  | ||||||
|                                  Internal) {} |  | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subtotp"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|         void DoPut() final; |  | ||||||
|     private: |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,259 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_subuser_handler.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
| #include "framework/RESTAPI_errors.h" |  | ||||||
| #include "SMSSender.h" |  | ||||||
| #include "ACLProcessor.h" |  | ||||||
| #include "AuthService.h" |  | ||||||
| #include "RESTAPI/RESTAPI_db_helpers.h" |  | ||||||
| #include "MFAServer.h" |  | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_subuser_handler::DoGet() { |  | ||||||
|         std::string Id = GetBinding("id", ""); |  | ||||||
|         if(Id.empty()) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(Id); |  | ||||||
|         std::string Arg; |  | ||||||
|         SecurityObjects::UserInfo   UInfo; |  | ||||||
|         if(HasParameter("byEmail",Arg) && Arg=="true") { |  | ||||||
|             if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) { |  | ||||||
|                 return NotFound(); |  | ||||||
|             } |  | ||||||
|         } else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |  | ||||||
|         Sanitize(UserInfo_, UInfo); |  | ||||||
|         UInfo.to_json(UserInfoObject); |  | ||||||
|         ReturnObject(UserInfoObject); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subuser_handler::DoDelete() { |  | ||||||
|         std::string Id = GetBinding("id", ""); |  | ||||||
|         if(Id.empty()) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo TargetUser; |  | ||||||
|         if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         AuthService()->DeleteSubUserFromCache(Id); |  | ||||||
|         StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email); |  | ||||||
|         StorageService()->SubPreferencesDB().DeleteRecord("id", Id); |  | ||||||
|         StorageService()->SubAvatarDB().DeleteRecord("id", Id); |  | ||||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); |  | ||||||
|         OK(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subuser_handler::DoPost() { |  | ||||||
|         std::string Id = GetBinding("id", ""); |  | ||||||
|         if(Id!="0") { |  | ||||||
|             return BadRequest(RESTAPI::Errors::IdMustBe0); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |  | ||||||
|         RESTAPI_utils::from_request(NewUser,*Request); |  | ||||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(NewUser.email); |  | ||||||
|         if(!Utils::ValidEMailAddress(NewUser.email)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!NewUser.currentPassword.empty()) { |  | ||||||
|             if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) { |  | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(NewUser.name.empty()) |  | ||||||
|             NewUser.name = NewUser.email; |  | ||||||
|  |  | ||||||
|         //  You cannot enable MFA during user creation |  | ||||||
|         NewUser.userTypeProprietaryInfo.mfa.enabled = false; |  | ||||||
|         NewUser.userTypeProprietaryInfo.mfa.method = ""; |  | ||||||
|         NewUser.userTypeProprietaryInfo.mobiles.clear(); |  | ||||||
|         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); |  | ||||||
|  |  | ||||||
|         if(!StorageService()->SubDB().CreateUser(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(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(Poco::format("User '%s' but not retrieved.",NewUser.email)); |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |  | ||||||
|         Sanitize(UserInfo_, NewUser); |  | ||||||
|         NewUser.to_json(UserInfoObject); |  | ||||||
|         ReturnObject(UserInfoObject); |  | ||||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_subuser_handler::DoPut() { |  | ||||||
|         std::string Id = GetBinding("id", ""); |  | ||||||
|         if(Id.empty()) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   Existing; |  | ||||||
|         if(!StorageService()->SubDB().GetUserById(Id,Existing)) { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { |  | ||||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |  | ||||||
|         auto RawObject = ParseStream(); |  | ||||||
|         if(!NewUser.from_json(RawObject)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // some basic validations |  | ||||||
|         if(RawObject->has("userRole") && |  | ||||||
|             (SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN || |  | ||||||
|             SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // The only valid things to change are: changePassword, name, |  | ||||||
|         AssignIfPresent(RawObject,"name", Existing.name); |  | ||||||
|         AssignIfPresent(RawObject,"description", Existing.description); |  | ||||||
|         AssignIfPresent(RawObject,"owner", Existing.owner); |  | ||||||
|         AssignIfPresent(RawObject,"location", Existing.location); |  | ||||||
|         AssignIfPresent(RawObject,"locale", Existing.locale); |  | ||||||
|         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); |  | ||||||
|         AssignIfPresent(RawObject,"suspended", Existing.suspended); |  | ||||||
|         AssignIfPresent(RawObject,"blackListed", Existing.blackListed); |  | ||||||
|  |  | ||||||
|         if(RawObject->has("userRole")) { |  | ||||||
|             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); |  | ||||||
|             if(NewRole!=Existing.userRole) { |  | ||||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|                 } |  | ||||||
|                 if(Id==UserInfo_.userinfo.id) { |  | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|                 } |  | ||||||
|                 Existing.userRole = NewRole; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(RawObject->has("notes")) { |  | ||||||
|             SecurityObjects::NoteInfoVec NIV; |  | ||||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); |  | ||||||
|             for(auto const &i:NIV) { |  | ||||||
|                 SecurityObjects::NoteInfo   ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note}; |  | ||||||
|                 Existing.notes.push_back(ii); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if(RawObject->has("currentPassword")) { |  | ||||||
|             if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) { |  | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); |  | ||||||
|             } |  | ||||||
|             if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) { |  | ||||||
|                 return BadRequest(RESTAPI::Errors::PasswordRejected); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(GetParameter("email_verification","false")=="true") { |  | ||||||
|             if(AuthService::VerifySubEmail(Existing)) |  | ||||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(RawObject->has("userTypeProprietaryInfo")) { |  | ||||||
|             if(NewUser.userTypeProprietaryInfo.mfa.enabled) { |  | ||||||
|                 if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) { |  | ||||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 bool ChangingMFA = |  | ||||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; |  | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; |  | ||||||
|  |  | ||||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); |  | ||||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { |  | ||||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                     if (PInfo->isArray("mobiles")) { |  | ||||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; |  | ||||||
|                     } |  | ||||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || |  | ||||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, |  | ||||||
|                                                     UserInfo_.userinfo.email)) { |  | ||||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); |  | ||||||
|                     } |  | ||||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); |  | ||||||
|                 } 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)) { |  | ||||||
|                         Existing.userTypeProprietaryInfo.authenticatorSecret = Secret; |  | ||||||
|                     } else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) { |  | ||||||
|                         // we allow someone to use their old secret |  | ||||||
|                     } else { |  | ||||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); |  | ||||||
|                     } |  | ||||||
|                 } else if (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(); |  | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { |  | ||||||
|             SecurityObjects::UserInfo   NewUserInfo; |  | ||||||
|             StorageService()->SubDB().GetUserById(Id,NewUserInfo); |  | ||||||
|             Poco::JSON::Object  ModifiedObject; |  | ||||||
|             Sanitize(UserInfo_, NewUserInfo); |  | ||||||
|             NewUserInfo.to_json(ModifiedObject); |  | ||||||
|             return ReturnObject(ModifiedObject); |  | ||||||
|         } |  | ||||||
|         BadRequest(RESTAPI::Errors::RecordNotUpdated); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_subuser_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string> |  | ||||||
|                          {Poco::Net::HTTPRequest::HTTP_POST, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_DELETE, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                           Server, |  | ||||||
|                           TransactionId, |  | ||||||
|                           Internal) {} |  | ||||||
|                           static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subuser/{id}"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final; |  | ||||||
|         void DoDelete() final; |  | ||||||
|         void DoPut() final; |  | ||||||
|     private: |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,55 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_subusers_handler.h" |  | ||||||
| #include "StorageService.h" |  | ||||||
| #include "framework/RESTAPI_protocol.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "RESTAPI/RESTAPI_db_helpers.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_subusers_handler::DoGet() { |  | ||||||
|         std::vector<SecurityObjects::UserInfo> Users; |  | ||||||
|         bool IdOnly = (GetParameter("idOnly","false")=="true"); |  | ||||||
|  |  | ||||||
|         if(QB_.Select.empty()) { |  | ||||||
|             Poco::JSON::Array ArrayObj; |  | ||||||
|             Poco::JSON::Object Answer; |  | ||||||
|             if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { |  | ||||||
|                 for (auto &i : Users) { |  | ||||||
|                     Poco::JSON::Object Obj; |  | ||||||
|                     if (IdOnly) { |  | ||||||
|                         ArrayObj.add(i.id); |  | ||||||
|                     } else { |  | ||||||
|                         Sanitize(UserInfo_, i); |  | ||||||
|                         i.to_json(Obj); |  | ||||||
|                         ArrayObj.add(Obj); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Answer.set(RESTAPI::Protocol::USERS, ArrayObj); |  | ||||||
|             } |  | ||||||
|             return ReturnObject(Answer); |  | ||||||
|         } else { |  | ||||||
|             Poco::JSON::Array ArrayObj; |  | ||||||
|             for(auto &i:SelectedRecords()) { |  | ||||||
|                 SecurityObjects::UserInfo   UInfo; |  | ||||||
|                 auto tI{i}; |  | ||||||
|                 if(StorageService()->SubDB().GetUserById(tI,UInfo)) { |  | ||||||
|                     Poco::JSON::Object Obj; |  | ||||||
|                     if (IdOnly) { |  | ||||||
|                         ArrayObj.add(UInfo.id); |  | ||||||
|                     } else { |  | ||||||
|                         Sanitize(UserInfo_, UInfo); |  | ||||||
|                         UInfo.to_json(Obj); |  | ||||||
|                         ArrayObj.add(Obj); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Poco::JSON::Object RetObj; |  | ||||||
|             RetObj.set(RESTAPI::Protocol::USERS, ArrayObj); |  | ||||||
|             return ReturnObject(RetObj); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_subusers_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_subusers_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string> |  | ||||||
|                          {Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                           Server, |  | ||||||
|                           TransactionId, |  | ||||||
|                           Internal) {} |  | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subusers"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|         void DoPut() final {}; |  | ||||||
|     }; |  | ||||||
| }; |  | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_system_endpoints_handler.h" | #include "RESTAPI_systemEndpoints_handler.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
| 
 | 
 | ||||||
|     void RESTAPI_system_endpoints_handler::DoGet() { |     void RESTAPI_systemEndpoints_handler::DoGet() { | ||||||
|         auto Services = MicroService::instance().GetServices(); |         auto Services = MicroService::instance().GetServices(); | ||||||
|         SecurityObjects::SystemEndpointList L; |         SecurityObjects::SystemEndpointList L; | ||||||
|         for(const auto &i:Services) { |         for(const auto &i:Services) { | ||||||
| @@ -2,19 +2,19 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H | ||||||
| 
 | 
 | ||||||
| #include "../framework/MicroService.h" | #include "../framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_system_endpoints_handler : public RESTAPIHandler { |     class RESTAPI_systemEndpoints_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_system_endpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, |                                  std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                                           Server, |                                                           Server, | ||||||
|                                                           TransactionId, |  | ||||||
|                                                           Internal) {} |                                                           Internal) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/systemEndpoints"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/systemEndpoints"}; }; | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
| @@ -23,3 +23,5 @@ namespace OpenWifi { | |||||||
|         void DoPut() final {}; |         void DoPut() final {}; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
 | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-31. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_totp_handler.h" |  | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     void RESTAPI_totp_handler::DoGet() { |  | ||||||
|  |  | ||||||
|         auto Reset = GetBoolParameter("reset",false); |  | ||||||
|         std::string QRCode; |  | ||||||
|  |  | ||||||
|         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { |  | ||||||
|             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); |  | ||||||
|         } |  | ||||||
|         return BadRequest(RESTAPI::Errors::InvalidCommand); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RESTAPI_totp_handler::DoPut() { |  | ||||||
|         auto Value = GetParameter("value",""); |  | ||||||
|         auto nextIndex = GetParameter("index",0); |  | ||||||
|         bool moreCodes=false; |  | ||||||
|  |  | ||||||
|         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(ErrorCode, ErrorText); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-31. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_totp_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_totp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|                 : RESTAPIHandler(bindings, L, |  | ||||||
|                                  std::vector<std::string> |  | ||||||
|                                          { |  | ||||||
|                                               Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                                               Poco::Net::HTTPRequest::HTTP_PUT, |  | ||||||
|                                               Poco::Net::HTTPRequest::HTTP_OPTIONS |  | ||||||
|                                           }, |  | ||||||
|                                  Server, |  | ||||||
|                                  TransactionId, |  | ||||||
|                                  Internal) {} |  | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/totp"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|         void DoPut() final; |  | ||||||
|     private: |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -4,16 +4,19 @@ | |||||||
|  |  | ||||||
| #include "RESTAPI_user_handler.h" | #include "RESTAPI_user_handler.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
|  | #include "Poco/JSON/Parser.h" | ||||||
| #include "framework/RESTAPI_errors.h" | #include "framework/RESTAPI_errors.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
| #include "ACLProcessor.h" | #include "ACLProcessor.h" | ||||||
| #include "AuthService.h" |  | ||||||
| #include "RESTAPI/RESTAPI_db_helpers.h" |  | ||||||
| #include "MFAServer.h" |  | ||||||
| #include "TotpCache.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static void FilterCredentials(SecurityObjects::UserInfo & U) { | ||||||
|  |         U.currentPassword.clear(); | ||||||
|  |         U.lastPasswords.clear(); | ||||||
|  |         U.oauthType.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void RESTAPI_user_handler::DoGet() { |     void RESTAPI_user_handler::DoGet() { | ||||||
|         std::string Id = GetBinding("id", ""); |         std::string Id = GetBinding("id", ""); | ||||||
|         if(Id.empty()) { |         if(Id.empty()) { | ||||||
| @@ -24,19 +27,15 @@ namespace OpenWifi { | |||||||
|         std::string Arg; |         std::string Arg; | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|         if(HasParameter("byEmail",Arg) && Arg=="true") { |         if(HasParameter("byEmail",Arg) && Arg=="true") { | ||||||
|             if(!StorageService()->UserDB().GetUserByEmail(Id,UInfo)) { |             if(!StorageService()->GetUserByEmail(Id,UInfo)) { | ||||||
|                 return NotFound(); |                 return NotFound(); | ||||||
|             } |             } | ||||||
|         } else if(!StorageService()->UserDB().GetUserById(Id,UInfo)) { |         } else if(!StorageService()->GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         Sanitize(UserInfo_, UInfo); |         FilterCredentials(UInfo); | ||||||
|         UInfo.to_json(UserInfoObject); |         UInfo.to_json(UserInfoObject); | ||||||
|         ReturnObject(UserInfoObject); |         ReturnObject(UserInfoObject); | ||||||
|     } |     } | ||||||
| @@ -48,7 +47,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo UInfo; |         SecurityObjects::UserInfo UInfo; | ||||||
|         if(!StorageService()->UserDB().GetUserById(Id,UInfo)) { |         if(!StorageService()->GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -56,14 +55,18 @@ namespace OpenWifi { | |||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) { |         if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         AuthService()->DeleteUserFromCache(Id); |         if(AuthService()->DeleteUserFromCache(UInfo.email)) { | ||||||
|         StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); |             // nothing to do | ||||||
|         StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id); |         } | ||||||
|         StorageService()->UserTokenDB().RevokeAllTokens(Id); |  | ||||||
|  |         StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||||
|  |  | ||||||
|  |         Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); | ||||||
|  |         StorageService()->RevokeAllTokens(UInfo.email); | ||||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); |         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||||
|         OK(); |         OK(); | ||||||
|     } |     } | ||||||
| @@ -76,18 +79,13 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |         SecurityObjects::UserInfo   NewUser; | ||||||
|         RESTAPI_utils::from_request(NewUser,*Request); |         RESTAPI_utils::from_request(NewUser,*Request); | ||||||
|  |  | ||||||
|         if(NewUser.userRole == SecurityObjects::UNKNOWN) { |         if(NewUser.userRole == SecurityObjects::UNKNOWN) { | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole==SecurityObjects::ROOT) { |  | ||||||
|             NewUser.owner = GetParameter("entity",""); |  | ||||||
|         } else { |  | ||||||
|             NewUser.owner = UserInfo_.userinfo.owner; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { |         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(NewUser.email); |         Poco::toLowerInPlace(NewUser.email); | ||||||
| @@ -104,13 +102,7 @@ namespace OpenWifi { | |||||||
|         if(NewUser.name.empty()) |         if(NewUser.name.empty()) | ||||||
|             NewUser.name = NewUser.email; |             NewUser.name = NewUser.email; | ||||||
|  |  | ||||||
|         //  You cannot enable MFA during user creation |         if(!StorageService()->CreateUser(NewUser.email,NewUser)) { | ||||||
|         NewUser.userTypeProprietaryInfo.mfa.enabled = false; |  | ||||||
|         NewUser.userTypeProprietaryInfo.mfa.method = ""; |  | ||||||
|         NewUser.userTypeProprietaryInfo.mobiles.clear(); |  | ||||||
|         NewUser.userTypeProprietaryInfo.authenticatorSecret.clear(); |  | ||||||
|  |  | ||||||
|         if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) { |  | ||||||
|             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); |             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); | ||||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); |             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||||
|         } |         } | ||||||
| @@ -118,16 +110,16 @@ namespace OpenWifi { | |||||||
|         if(GetParameter("email_verification","false")=="true") { |         if(GetParameter("email_verification","false")=="true") { | ||||||
|             if(AuthService::VerifyEmail(NewUser)) |             if(AuthService::VerifyEmail(NewUser)) | ||||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); |                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); | ||||||
|             StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser); |             StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) { |         if(!StorageService()->GetUserByEmail(NewUser.email, NewUser)) { | ||||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); |             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         Sanitize(UserInfo_, NewUser); |         FilterCredentials(NewUser); | ||||||
|         NewUser.to_json(UserInfoObject); |         NewUser.to_json(UserInfoObject); | ||||||
|         ReturnObject(UserInfoObject); |         ReturnObject(UserInfoObject); | ||||||
|         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); |         Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email)); | ||||||
| @@ -140,7 +132,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   Existing; |         SecurityObjects::UserInfo   Existing; | ||||||
|         if(!StorageService()->UserDB().GetUserById(Id,Existing)) { |         if(!StorageService()->GetUserById(Id,Existing)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -159,15 +151,10 @@ namespace OpenWifi { | |||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(RawObject->has("owner")) { |  | ||||||
|             if (UserInfo_.userinfo.userRole == SecurityObjects::ROOT && Existing.owner.empty()) { |  | ||||||
|                 AssignIfPresent(RawObject, "owner", Existing.owner); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // The only valid things to change are: changePassword, name, |         // The only valid things to change are: changePassword, name, | ||||||
|         AssignIfPresent(RawObject,"name", Existing.name); |         AssignIfPresent(RawObject,"name", Existing.name); | ||||||
|         AssignIfPresent(RawObject,"description", Existing.description); |         AssignIfPresent(RawObject,"description", Existing.description); | ||||||
|  |         AssignIfPresent(RawObject,"owner", Existing.owner); | ||||||
|         AssignIfPresent(RawObject,"location", Existing.location); |         AssignIfPresent(RawObject,"location", Existing.location); | ||||||
|         AssignIfPresent(RawObject,"locale", Existing.locale); |         AssignIfPresent(RawObject,"locale", Existing.locale); | ||||||
|         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); |         AssignIfPresent(RawObject,"changePassword", Existing.changePassword); | ||||||
| @@ -180,7 +167,7 @@ namespace OpenWifi { | |||||||
|                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { |                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|                 } |                 } | ||||||
|                 if(Id==UserInfo_.userinfo.id) { |                 if(Id==UserInfo_.userinfo.Id) { | ||||||
|                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|                 } |                 } | ||||||
|                 Existing.userRole = NewRole; |                 Existing.userRole = NewRole; | ||||||
| @@ -210,56 +197,42 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(RawObject->has("userTypeProprietaryInfo")) { |         if(RawObject->has("userTypeProprietaryInfo")) { | ||||||
|             if(NewUser.userTypeProprietaryInfo.mfa.enabled) { |             bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||||
|                 if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) { |  | ||||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 bool ChangingMFA = |             Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||||
|                         NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; |  | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; |  | ||||||
|  |  | ||||||
|                 auto PropInfo = RawObject->get("userTypeProprietaryInfo"); |             auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||||
|                 if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) { |             auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||||
|                     auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                     if (PInfo->isArray("mobiles")) { |             if(PInfo->isArray("mobiles")) { | ||||||
|                         Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; |                 Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||||
|                     } |             } | ||||||
|                     if (NewUser.userTypeProprietaryInfo.mobiles.empty() || |  | ||||||
|                         !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number, |             if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){ | ||||||
|                                                     UserInfo_.userinfo.email)) { |                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||||
|                         return BadRequest(RESTAPI::Errors::NeedMobileNumber); |             } | ||||||
|                     } |  | ||||||
|                     Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); |             if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) { | ||||||
|                 } else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) { |                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||||
|                     std::string Secret; |             } | ||||||
|                     Existing.userTypeProprietaryInfo.mobiles.clear(); |  | ||||||
|                     if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) { |             if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) { | ||||||
|                         Existing.userTypeProprietaryInfo.authenticatorSecret = Secret; |                 if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) { | ||||||
|                     } else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) { |                     return BadRequest("Unknown MFA method"); | ||||||
|                         // we allow someone to use their old secret |  | ||||||
|                     } else { |  | ||||||
|                         return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete); |  | ||||||
|                     } |  | ||||||
|                 } 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.method=NewUser.userTypeProprietaryInfo.mfa.method; | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = true; |             } | ||||||
|             } else { |  | ||||||
|                 Existing.userTypeProprietaryInfo.authenticatorSecret.clear(); |             if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) { | ||||||
|                 Existing.userTypeProprietaryInfo.mobiles.clear(); |                 return BadRequest("Illegal MFA method"); | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.enabled = false; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { |         if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||||
|             SecurityObjects::UserInfo   NewUserInfo; |             SecurityObjects::UserInfo   NewUserInfo; | ||||||
|             StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); |             StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||||
|             Poco::JSON::Object  ModifiedObject; |             Poco::JSON::Object  ModifiedObject; | ||||||
|             Sanitize(UserInfo_, NewUserInfo); |             FilterCredentials(NewUserInfo); | ||||||
|             NewUserInfo.to_json(ModifiedObject); |             NewUserInfo.to_json(ModifiedObject); | ||||||
|             return ReturnObject(ModifiedObject); |             return ReturnObject(ModifiedObject); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -2,14 +2,15 @@ | |||||||
| // Created by stephane bourque on 2021-06-21. | // Created by stephane bourque on 2021-06-21. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_USER_HANDLER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_USER_HANDLER_H | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_user_handler : public RESTAPIHandler { |     class RESTAPI_user_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_POST, |                                          {Poco::Net::HTTPRequest::HTTP_POST, | ||||||
| @@ -18,7 +19,6 @@ namespace OpenWifi { | |||||||
|                                           Poco::Net::HTTPRequest::HTTP_DELETE, |                                           Poco::Net::HTTPRequest::HTTP_DELETE, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|                                           TransactionId, |  | ||||||
|                                           Internal) {} |                                           Internal) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; }; | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
| @@ -29,3 +29,6 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_USER_HANDLER_H | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ | |||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/RESTAPI_protocol.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "RESTAPI/RESTAPI_db_helpers.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_users_handler::DoGet() { |     void RESTAPI_users_handler::DoGet() { | ||||||
| @@ -16,13 +15,15 @@ namespace OpenWifi { | |||||||
|         if(QB_.Select.empty()) { |         if(QB_.Select.empty()) { | ||||||
|             Poco::JSON::Array ArrayObj; |             Poco::JSON::Array ArrayObj; | ||||||
|             Poco::JSON::Object Answer; |             Poco::JSON::Object Answer; | ||||||
|             if (StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users)) { |             if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||||
|                 for (auto &i : Users) { |                 for (auto &i : Users) { | ||||||
|                     Poco::JSON::Object Obj; |                     Poco::JSON::Object Obj; | ||||||
|                     if (IdOnly) { |                     if (IdOnly) { | ||||||
|                         ArrayObj.add(i.id); |                         ArrayObj.add(i.Id); | ||||||
|                     } else { |                     } else { | ||||||
|                         Sanitize(UserInfo_, i); |                         i.currentPassword.clear(); | ||||||
|  |                         i.lastPasswords.clear(); | ||||||
|  |                         i.oauthType.clear(); | ||||||
|                         i.to_json(Obj); |                         i.to_json(Obj); | ||||||
|                         ArrayObj.add(Obj); |                         ArrayObj.add(Obj); | ||||||
|                     } |                     } | ||||||
| @@ -31,16 +32,18 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|         } else { |         } else { | ||||||
|  |             Types::StringVec IDs = Utils::Split(QB_.Select); | ||||||
|             Poco::JSON::Array ArrayObj; |             Poco::JSON::Array ArrayObj; | ||||||
|             for(auto &i:SelectedRecords()) { |             for(auto &i:IDs) { | ||||||
|                 SecurityObjects::UserInfo   UInfo; |                 SecurityObjects::UserInfo   UInfo; | ||||||
|                 auto tI{i}; |                 if(StorageService()->GetUserById(i,UInfo)) { | ||||||
|                 if(StorageService()->UserDB().GetUserById(i,UInfo)) { |  | ||||||
|                     Poco::JSON::Object Obj; |                     Poco::JSON::Object Obj; | ||||||
|                     if (IdOnly) { |                     if (IdOnly) { | ||||||
|                         ArrayObj.add(UInfo.id); |                         ArrayObj.add(UInfo.Id); | ||||||
|                     } else { |                     } else { | ||||||
|                         Sanitize(UserInfo_, UInfo); |                         UInfo.currentPassword.clear(); | ||||||
|  |                         UInfo.lastPasswords.clear(); | ||||||
|  |                         UInfo.oauthType.clear(); | ||||||
|                         UInfo.to_json(Obj); |                         UInfo.to_json(Obj); | ||||||
|                         ArrayObj.add(Obj); |                         ArrayObj.add(Obj); | ||||||
|                     } |                     } | ||||||
|   | |||||||
| @@ -2,20 +2,20 @@ | |||||||
| // Created by stephane bourque on 2021-06-21. | // Created by stephane bourque on 2021-06-21. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_USERS_HANDLER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_USERS_HANDLER_H | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_users_handler : public RESTAPIHandler { |     class RESTAPI_users_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                  {Poco::Net::HTTPRequest::HTTP_GET, |                                  {Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                   Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                   Server, |                                   Server, | ||||||
|                                   TransactionId, |  | ||||||
|                                   Internal) {} |                                   Internal) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; }; | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
| @@ -25,3 +25,5 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_USERS_HANDLER_H | ||||||
|   | |||||||
| @@ -2,11 +2,11 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include "RESTAPI_validate_token_handler.h" | #include "RESTAPI_validateToken_handler.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     void RESTAPI_validate_token_handler::DoGet() { |     void RESTAPI_validateToken_handler::DoGet() { | ||||||
|         Poco::URI URI(Request->getURI()); |         Poco::URI URI(Request->getURI()); | ||||||
|         auto Parameters = URI.getQueryParameters(); |         auto Parameters = URI.getQueryParameters(); | ||||||
|         for(auto const &i:Parameters) { |         for(auto const &i:Parameters) { | ||||||
| @@ -2,20 +2,20 @@ | |||||||
| // Created by stephane bourque on 2021-07-01.
 | // Created by stephane bourque on 2021-07-01.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #ifndef UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H | ||||||
|  | #define UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H | ||||||
| 
 | 
 | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class RESTAPI_validate_token_handler : public RESTAPIHandler { |     class RESTAPI_validateToken_handler : public RESTAPIHandler { | ||||||
|     public: |     public: | ||||||
|         RESTAPI_validate_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |         RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal) | ||||||
|                 : RESTAPIHandler(bindings, L, |                 : RESTAPIHandler(bindings, L, | ||||||
|                                  std::vector<std::string> |                                  std::vector<std::string> | ||||||
|                                          {Poco::Net::HTTPRequest::HTTP_GET, |                                          {Poco::Net::HTTPRequest::HTTP_GET, | ||||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                           Server, |                                           Server, | ||||||
|                                           TransactionId, |  | ||||||
|                                           Internal) {}; |                                           Internal) {}; | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateToken"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateToken"}; }; | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
| @@ -25,3 +25,4 @@ namespace OpenWifi { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #endif //UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
 | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_validate_sub_token_handler.h" |  | ||||||
| #include "AuthService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     void RESTAPI_validate_sub_token_handler::DoGet() { |  | ||||||
|         Poco::URI URI(Request->getURI()); |  | ||||||
|         auto Parameters = URI.getQueryParameters(); |  | ||||||
|         for(auto const &i:Parameters) { |  | ||||||
|             if (i.first == "token") { |  | ||||||
|                 //  can we find this token? |  | ||||||
|                 SecurityObjects::UserInfoAndPolicy SecObj; |  | ||||||
|                 bool Expired = false; |  | ||||||
|                 if (AuthService()->IsValidSubToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) { |  | ||||||
|                     Poco::JSON::Object Obj; |  | ||||||
|                     SecObj.to_json(Obj); |  | ||||||
|                     return ReturnObject(Obj); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return NotFound(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     class RESTAPI_validate_sub_token_handler : public RESTAPIHandler { |  | ||||||
|     public: |  | ||||||
|         RESTAPI_validate_sub_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) |  | ||||||
|         : RESTAPIHandler(bindings, L, |  | ||||||
|                          std::vector<std::string> |  | ||||||
|                          {Poco::Net::HTTPRequest::HTTP_GET, |  | ||||||
|                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, |  | ||||||
|                           Server, |  | ||||||
|                           TransactionId, |  | ||||||
|                           Internal) {}; |  | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateSubToken"}; }; |  | ||||||
|         void DoGet() final; |  | ||||||
|         void DoPost() final {}; |  | ||||||
|         void DoDelete() final {}; |  | ||||||
|         void DoPut() final {}; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,178 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-12-07. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_CertObjects.h" |  | ||||||
|  |  | ||||||
| using OpenWifi::RESTAPI_utils::field_to_json; |  | ||||||
| using OpenWifi::RESTAPI_utils::field_from_json; |  | ||||||
|  |  | ||||||
| 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); |  | ||||||
|             field_to_json(Obj,"creator", creator); |  | ||||||
|             field_to_json(Obj,"type", type); |  | ||||||
|             field_to_json(Obj,"status", status); |  | ||||||
|             field_to_json(Obj,"certificate", certificate); |  | ||||||
|             field_to_json(Obj,"key", key); |  | ||||||
|             field_to_json(Obj,"devid", devid); |  | ||||||
|             field_to_json(Obj,"cas", cas); |  | ||||||
|             field_to_json(Obj,"manufacturer", manufacturer); |  | ||||||
|             field_to_json(Obj,"model", model); |  | ||||||
|             field_to_json(Obj,"redirector", redirector); |  | ||||||
|             field_to_json(Obj,"commonName", commonName); |  | ||||||
|             field_to_json(Obj,"certificateId", certificateId); |  | ||||||
|             field_to_json(Obj,"batch", batch); |  | ||||||
|             field_to_json(Obj,"created", created); |  | ||||||
|             field_to_json(Obj,"modified", modified); |  | ||||||
|             field_to_json(Obj,"revoked", revoked); |  | ||||||
|             field_to_json(Obj,"revokeCount", revokeCount); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|             try { |  | ||||||
|                 field_from_json(Obj,"id", id); |  | ||||||
|                 field_from_json(Obj,"entity", entity); |  | ||||||
|                 field_from_json(Obj,"creator", creator); |  | ||||||
|                 field_from_json(Obj,"type", type); |  | ||||||
|                 field_from_json(Obj,"status", status); |  | ||||||
|                 field_from_json(Obj,"certificate", certificate); |  | ||||||
|                 field_from_json(Obj,"key", key); |  | ||||||
|                 field_from_json(Obj,"devid", devid); |  | ||||||
|                 field_from_json(Obj,"cas", cas); |  | ||||||
|                 field_from_json(Obj,"manufacturer", manufacturer); |  | ||||||
|                 field_from_json(Obj,"model", model); |  | ||||||
|                 field_from_json(Obj,"redirector", redirector); |  | ||||||
|                 field_from_json(Obj,"commonName", commonName); |  | ||||||
|                 field_from_json(Obj,"certificateId", certificateId); |  | ||||||
|                 field_from_json(Obj,"batch", batch); |  | ||||||
|                 field_from_json(Obj,"created", created); |  | ||||||
|                 field_from_json(Obj,"modified", modified); |  | ||||||
|                 field_from_json(Obj,"revoked", revoked); |  | ||||||
|                 field_from_json(Obj,"revokeCount", revokeCount); |  | ||||||
|                 return true; |  | ||||||
|             } catch (...) { |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         void EntityEntry::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|             field_to_json(Obj,"id", id); |  | ||||||
|             field_to_json(Obj,"creator", creator); |  | ||||||
|             field_to_json(Obj,"name", name); |  | ||||||
|             field_to_json(Obj,"description", description); |  | ||||||
|             field_to_json(Obj,"defaultRedirector", defaultRedirector); |  | ||||||
|             field_to_json(Obj,"apiKey", apiKey); |  | ||||||
|             field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); |  | ||||||
|             field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); |  | ||||||
|             field_to_json(Obj,"organization", organization); |  | ||||||
|             field_to_json(Obj,"created", created); |  | ||||||
|             field_to_json(Obj,"modified", modified); |  | ||||||
|             field_to_json(Obj,"suspended", suspended); |  | ||||||
|             field_to_json(Obj,"deleted", deleted); |  | ||||||
|             field_to_json(Obj,"notes", notes); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|             try { |  | ||||||
|                 field_from_json(Obj,"id", id); |  | ||||||
|                 field_from_json(Obj,"creator", creator); |  | ||||||
|                 field_from_json(Obj,"name", name); |  | ||||||
|                 field_from_json(Obj,"description", description); |  | ||||||
|                 field_from_json(Obj,"defaultRedirector", defaultRedirector); |  | ||||||
|                 field_from_json(Obj,"apiKey", apiKey); |  | ||||||
|                 field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); |  | ||||||
|                 field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); |  | ||||||
|                 field_from_json(Obj,"organization", organization); |  | ||||||
|                 field_from_json(Obj,"created", created); |  | ||||||
|                 field_from_json(Obj,"modified", modified); |  | ||||||
|                 field_from_json(Obj,"suspended", suspended); |  | ||||||
|                 field_from_json(Obj,"deleted", deleted); |  | ||||||
|                 field_from_json(Obj,"notes", notes); |  | ||||||
|                 return true; |  | ||||||
|             } catch (...) { |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         void BatchEntry::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|             field_to_json(Obj,"id", id); |  | ||||||
|             field_to_json(Obj,"entity", entity); |  | ||||||
|             field_to_json(Obj,"creator", creator); |  | ||||||
|             field_to_json(Obj,"name", name); |  | ||||||
|             field_to_json(Obj,"description", description); |  | ||||||
|             field_to_json(Obj,"manufacturer", manufacturer); |  | ||||||
|             field_to_json(Obj,"model", model); |  | ||||||
|             field_to_json(Obj,"redirector", redirector); |  | ||||||
|             field_to_json(Obj,"commonNames", commonNames); |  | ||||||
|             field_to_json(Obj,"jobHistory", jobHistory); |  | ||||||
|             field_to_json(Obj,"notes", notes); |  | ||||||
|             field_to_json(Obj,"submitted", submitted); |  | ||||||
|             field_to_json(Obj,"started", started); |  | ||||||
|             field_to_json(Obj,"completed", completed); |  | ||||||
|             field_to_json(Obj,"modified", modified); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|             try { |  | ||||||
|                 field_from_json(Obj,"id", id); |  | ||||||
|                 field_from_json(Obj,"entity", entity); |  | ||||||
|                 field_from_json(Obj,"creator", creator); |  | ||||||
|                 field_from_json(Obj,"name", name); |  | ||||||
|                 field_from_json(Obj,"description", description); |  | ||||||
|                 field_from_json(Obj,"manufacturer", manufacturer); |  | ||||||
|                 field_from_json(Obj,"model", model); |  | ||||||
|                 field_from_json(Obj,"redirector", redirector); |  | ||||||
|                 field_from_json(Obj,"commonNames", commonNames); |  | ||||||
|                 field_from_json(Obj,"jobHistory", jobHistory); |  | ||||||
|                 field_from_json(Obj,"notes", notes); |  | ||||||
|                 field_from_json(Obj,"submitted", submitted); |  | ||||||
|                 field_from_json(Obj,"started", started); |  | ||||||
|                 field_from_json(Obj,"completed", completed); |  | ||||||
|                 field_from_json(Obj,"modified", modified); |  | ||||||
|                 return true; |  | ||||||
|             } catch (...) { |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         void JobEntry::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|             field_to_json(Obj,"id", id); |  | ||||||
|             field_to_json(Obj,"entity", entity); |  | ||||||
|             field_to_json(Obj,"creator", creator); |  | ||||||
|             field_to_json(Obj,"batch", batch); |  | ||||||
|             field_to_json(Obj,"commonNames", commonNames); |  | ||||||
|             field_to_json(Obj,"completedNames", completedNames); |  | ||||||
|             field_to_json(Obj,"errorNames", errorNames); |  | ||||||
|             field_to_json(Obj,"status", status); |  | ||||||
|             field_to_json(Obj,"command", command); |  | ||||||
|             field_to_json(Obj,"parameters", parameters); |  | ||||||
|             field_to_json(Obj,"submitted", submitted); |  | ||||||
|             field_to_json(Obj,"started", started); |  | ||||||
|             field_to_json(Obj,"completed", completed); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|             try { |  | ||||||
|                 field_from_json(Obj,"id", id); |  | ||||||
|                 field_from_json(Obj,"entity", entity); |  | ||||||
|                 field_from_json(Obj,"creator", creator); |  | ||||||
|                 field_from_json(Obj,"batch", batch); |  | ||||||
|                 field_from_json(Obj,"commonNames", commonNames); |  | ||||||
|                 field_from_json(Obj,"completedNames", completedNames); |  | ||||||
|                 field_from_json(Obj,"errorNames", errorNames); |  | ||||||
|                 field_from_json(Obj,"status", status); |  | ||||||
|                 field_from_json(Obj,"command", command); |  | ||||||
|                 field_from_json(Obj,"parameters", parameters); |  | ||||||
|                 field_from_json(Obj,"submitted", submitted); |  | ||||||
|                 field_from_json(Obj,"started", started); |  | ||||||
|                 field_from_json(Obj,"completed", completed); |  | ||||||
|                 return true; |  | ||||||
|             } catch (...) { |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,101 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-12-07. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <string> |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "framework/OpenWifiTypes.h" |  | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     namespace CertObjects { |  | ||||||
|  |  | ||||||
|         struct CertificateEntry { |  | ||||||
|             OpenWifi::Types::UUID_t         id; |  | ||||||
|             OpenWifi::Types::UUID_t         entity; |  | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             std::string                     type; |  | ||||||
|             std::string                     status; |  | ||||||
|             std::string                     certificate; |  | ||||||
|             std::string                     key; |  | ||||||
|             std::string                     devid; |  | ||||||
|             std::string                     cas; |  | ||||||
|             std::string                     manufacturer; |  | ||||||
|             std::string                     model; |  | ||||||
|             std::string                     redirector; |  | ||||||
|             std::string                     commonName; |  | ||||||
|             std::string                     certificateId; |  | ||||||
|             OpenWifi::Types::UUID_t         batch; |  | ||||||
|             uint64_t                        created = 0; |  | ||||||
|             uint64_t                        modified = 0; |  | ||||||
|             uint64_t                        revoked = 0; |  | ||||||
|             uint64_t                        revokeCount = 0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct EntityEntry { |  | ||||||
|             OpenWifi::Types::UUID_t         id; |  | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             std::string                     name; |  | ||||||
|             std::string                     description; |  | ||||||
|             std::string                     defaultRedirector; |  | ||||||
|             std::string                     apiKey; |  | ||||||
|             std::string                     serverEnrollmentProfile; |  | ||||||
|             std::string                     clientEnrollmentProfile; |  | ||||||
|             std::string                     organization; |  | ||||||
|             SecurityObjects::NoteInfoVec    notes; |  | ||||||
|             bool                            suspended=false; |  | ||||||
|             bool                            deleted=false; |  | ||||||
|             uint64_t                        created = 0 ; |  | ||||||
|             uint64_t                        modified = 0 ; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct BatchEntry { |  | ||||||
|             OpenWifi::Types::UUID_t         id; |  | ||||||
|             OpenWifi::Types::UUID_t         entity; |  | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             std::string                     name; |  | ||||||
|             std::string                     description; |  | ||||||
|             std::string                     manufacturer; |  | ||||||
|             std::string                     model; |  | ||||||
|             std::string                     redirector; |  | ||||||
|             std::vector<std::string>        commonNames; |  | ||||||
|             std::vector<std::string>        jobHistory; |  | ||||||
|             SecurityObjects::NoteInfoVec    notes; |  | ||||||
|             uint64_t                        submitted = 0 ; |  | ||||||
|             uint64_t                        started = 0 ; |  | ||||||
|             uint64_t                        completed = 0 ; |  | ||||||
|             uint64_t                        modified = 0 ; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct JobEntry { |  | ||||||
|             OpenWifi::Types::UUID_t         id; |  | ||||||
|             OpenWifi::Types::UUID_t         entity; |  | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             OpenWifi::Types::UUID_t         batch; |  | ||||||
|             std::string                     command; |  | ||||||
|             OpenWifi::Types::StringVec      commonNames; |  | ||||||
|             OpenWifi::Types::StringVec      completedNames; |  | ||||||
|             OpenWifi::Types::StringVec      errorNames; |  | ||||||
|             Types::StringPairVec            parameters; |  | ||||||
|             std::string                     status; |  | ||||||
|             uint64_t                        submitted=0; |  | ||||||
|             uint64_t                        started=0; |  | ||||||
|             uint64_t                        completed=0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -29,7 +29,7 @@ namespace OpenWifi::FMSObjects { | |||||||
|         std::string     location; |         std::string     location; | ||||||
|         std::string     uploader; |         std::string     uploader; | ||||||
|         std::string     digest; |         std::string     digest; | ||||||
|         bool            latest=0; |         bool            latest=false; | ||||||
|         SecurityObjects::NoteInfoVec    notes; |         SecurityObjects::NoteInfoVec    notes; | ||||||
|         uint64_t        created=0; |         uint64_t        created=0; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ | |||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
| #ifdef	TIP_GATEWAY_SERVICE | #ifdef	TIP_GATEWAY_SERVICE | ||||||
| #include "DeviceRegistry.h" | #include "DeviceRegistry.h" | ||||||
| #include "CapabilitiesCache.h" |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "RESTAPI_GWobjects.h" | #include "RESTAPI_GWobjects.h" | ||||||
| @@ -27,7 +26,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 	void Device::to_json(Poco::JSON::Object &Obj) const { | 	void Device::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||||
| #ifdef TIP_GATEWAY_SERVICE | #ifdef TIP_GATEWAY_SERVICE | ||||||
| 		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible)); | 		field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible)); | ||||||
| #endif | #endif | ||||||
| 		field_to_json(Obj,"macAddress", MACAddress); | 		field_to_json(Obj,"macAddress", MACAddress); | ||||||
| 		field_to_json(Obj,"manufacturer", Manufacturer); | 		field_to_json(Obj,"manufacturer", Manufacturer); | ||||||
| @@ -146,7 +145,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"custom", Custom); | 		field_to_json(Obj,"custom", Custom); | ||||||
| 		field_to_json(Obj,"waitingForFile", WaitingForFile); | 		field_to_json(Obj,"waitingForFile", WaitingForFile); | ||||||
| 		field_to_json(Obj,"attachFile", AttachDate); | 		field_to_json(Obj,"attachFile", AttachDate); | ||||||
| 		field_to_json(Obj,"executionTime", executionTime); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { | 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -181,6 +179,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | 	void ConnectionState::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  | 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||||
| 		field_to_json(Obj,"ipAddress", Address); | 		field_to_json(Obj,"ipAddress", Address); | ||||||
| 		field_to_json(Obj,"txBytes", TX); | 		field_to_json(Obj,"txBytes", TX); | ||||||
| 		field_to_json(Obj,"rxBytes", RX); | 		field_to_json(Obj,"rxBytes", RX); | ||||||
| @@ -191,10 +190,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"lastContact", LastContact); | 		field_to_json(Obj,"lastContact", LastContact); | ||||||
| 		field_to_json(Obj,"associations_2G", Associations_2G); | 		field_to_json(Obj,"associations_2G", Associations_2G); | ||||||
| 		field_to_json(Obj,"associations_5G", Associations_5G); | 		field_to_json(Obj,"associations_5G", Associations_5G); | ||||||
| 		field_to_json(Obj,"webSocketClients", webSocketClients); |  | ||||||
| 		field_to_json(Obj,"websocketPackets", websocketPackets); |  | ||||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); |  | ||||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); |  | ||||||
|  |  | ||||||
| 		switch(VerifiedCertificate) { | 		switch(VerifiedCertificate) { | ||||||
| 			case NO_CERTIFICATE: | 			case NO_CERTIFICATE: | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRAL_RESTAPI_OBJECTS_H | ||||||
|  | #define UCENTRAL_RESTAPI_OBJECTS_H | ||||||
|  |  | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| @@ -22,6 +23,7 @@ namespace OpenWifi::GWObjects { | |||||||
|  |  | ||||||
| 	struct ConnectionState { | 	struct ConnectionState { | ||||||
| 		uint64_t MessageCount = 0 ; | 		uint64_t MessageCount = 0 ; | ||||||
|  | 		std::string SerialNumber; | ||||||
| 		std::string Address; | 		std::string Address; | ||||||
| 		uint64_t UUID = 0 ; | 		uint64_t UUID = 0 ; | ||||||
| 		uint64_t PendingUUID = 0 ; | 		uint64_t PendingUUID = 0 ; | ||||||
| @@ -33,10 +35,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string Firmware; | 		std::string Firmware; | ||||||
| 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | 		CertificateValidation VerifiedCertificate = NO_CERTIFICATE; | ||||||
| 		std::string Compatible; | 		std::string Compatible; | ||||||
| 		uint64_t 	kafkaClients=0; |  | ||||||
| 		uint64_t 	webSocketClients=0; |  | ||||||
| 		uint64_t 	kafkaPackets=0; |  | ||||||
| 		uint64_t 	websocketPackets=0; |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -52,11 +50,11 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string Firmware; | 		std::string Firmware; | ||||||
| 		std::string Compatible; | 		std::string Compatible; | ||||||
| 		std::string FWUpdatePolicy; | 		std::string FWUpdatePolicy; | ||||||
| 		uint64_t UUID = 0 ; | 		uint64_t UUID; | ||||||
| 		uint64_t CreationTimestamp = 0 ; | 		uint64_t CreationTimestamp; | ||||||
| 		uint64_t LastConfigurationChange = 0 ; | 		uint64_t LastConfigurationChange; | ||||||
| 		uint64_t LastConfigurationDownload = 0 ; | 		uint64_t LastConfigurationDownload; | ||||||
| 		uint64_t LastFWUpdate = 0 ; | 		uint64_t LastFWUpdate; | ||||||
| 		std::string Venue; | 		std::string Venue; | ||||||
| 		std::string DevicePassword; | 		std::string DevicePassword; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| @@ -67,25 +65,25 @@ namespace OpenWifi::GWObjects { | |||||||
|  |  | ||||||
| 	struct Statistics { | 	struct Statistics { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		uint64_t 	UUID = 0 ; | 		uint64_t 	UUID; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Recorded = 0; | 		uint64_t 	Recorded; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct HealthCheck { | 	struct HealthCheck { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		uint64_t 	UUID = 0 ; | 		uint64_t 	UUID; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Recorded = 0 ; | 		uint64_t 	Recorded; | ||||||
| 		uint64_t 	Sanity = 0 ; | 		uint64_t 	Sanity; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct Capabilities { | 	struct Capabilities { | ||||||
| 		std::string Capabilities; | 		std::string Capabilities; | ||||||
| 		uint64_t 	FirstUpdate = 0 ; | 		uint64_t 	FirstUpdate; | ||||||
| 		uint64_t 	LastUpdate = 0 ; | 		uint64_t 	LastUpdate; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -103,17 +101,17 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		std::string Log; | 		std::string Log; | ||||||
| 		std::string Data; | 		std::string Data; | ||||||
| 		uint64_t 	Severity = 0 ; | 		uint64_t 	Severity; | ||||||
| 		uint64_t 	Recorded = 0 ; | 		uint64_t 	Recorded; | ||||||
| 		uint64_t 	LogType = 0 ; | 		uint64_t 	LogType; | ||||||
| 		uint64_t 	UUID = 0 ; | 		uint64_t 	UUID; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct DefaultConfiguration { | 	struct DefaultConfiguration { | ||||||
| 		std::string Name; | 		std::string Name; | ||||||
| 		std::string Configuration; | 		std::string Configuration; | ||||||
| 		Types::StringVec Models; | 		std::string Models; | ||||||
| 		std::string Description; | 		std::string Description; | ||||||
| 		uint64_t 	Created; | 		uint64_t 	Created; | ||||||
| 		uint64_t 	LastModified; | 		uint64_t 	LastModified; | ||||||
| @@ -140,7 +138,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 		uint64_t AttachDate = 0 ; | 		uint64_t AttachDate = 0 ; | ||||||
| 		uint64_t AttachSize = 0 ; | 		uint64_t AttachSize = 0 ; | ||||||
| 		std::string AttachType; | 		std::string AttachType; | ||||||
| 		double 		executionTime = 0.0; |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -156,20 +153,20 @@ namespace OpenWifi::GWObjects { | |||||||
| 	struct RttySessionDetails { | 	struct RttySessionDetails { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		std::string Server; | 		std::string Server; | ||||||
| 		uint64_t 	Port = 0 ; | 		uint64_t 	Port; | ||||||
| 		std::string Token; | 		std::string Token; | ||||||
| 		uint64_t 	TimeOut = 0 ; | 		uint64_t 	TimeOut; | ||||||
| 		std::string ConnectionId; | 		std::string ConnectionId; | ||||||
| 		uint64_t 	Started = 0 ; | 		uint64_t 	Started; | ||||||
| 		std::string CommandUUID; | 		std::string CommandUUID; | ||||||
| 		uint64_t 	ViewPort = 0 ; | 		uint64_t 	ViewPort; | ||||||
| 		std::string DevicePassword; | 		std::string DevicePassword; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct Dashboard { | 	struct Dashboard { | ||||||
| 		uint64_t 		  snapshot = 0 ; | 		uint64_t 		  snapshot; | ||||||
| 		uint64_t 		  numberOfDevices = 0 ; | 		uint64_t 		  numberOfDevices; | ||||||
| 		Types::CountedMap commands; | 		Types::CountedMap commands; | ||||||
| 		Types::CountedMap upTimes; | 		Types::CountedMap upTimes; | ||||||
| 		Types::CountedMap memoryUsed; | 		Types::CountedMap memoryUsed; | ||||||
| @@ -194,3 +191,5 @@ namespace OpenWifi::GWObjects { | |||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //UCENTRAL_RESTAPI_OBJECTS_H | ||||||
|   | |||||||
| @@ -309,7 +309,6 @@ namespace OpenWifi::ProvObjects { | |||||||
|         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|         field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"rrm",rrm); | ||||||
|         field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         field_to_json( Obj,"state",state); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -327,7 +326,6 @@ namespace OpenWifi::ProvObjects { | |||||||
|             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|             field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"rrm",rrm); | ||||||
|             field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             field_from_json( Obj,"state",state); |  | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -335,20 +333,6 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void InventoryTagList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json( Obj,"taglist",taglist); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json( Obj,"taglist",taglist); |  | ||||||
|             return false; |  | ||||||
|         } catch (...) { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { |     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json( Obj,"name", name); |         field_to_json( Obj,"name", name); | ||||||
|         field_to_json( Obj,"description", description); |         field_to_json( Obj,"description", description); | ||||||
| @@ -456,11 +440,11 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UuidList::to_json(Poco::JSON::Object &Obj) const { |     void UserList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj, "list", list); |         field_to_json(Obj, "list", list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool UuidList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool UserList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj, "list", list); |             field_from_json(Obj, "list", list); | ||||||
|             return true; |             return true; | ||||||
| @@ -470,46 +454,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         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 { |     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "users", users); |         field_to_json(Obj, "users", users); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "roles", roles); |  | ||||||
|         field_to_json(Obj, "access", access); |         field_to_json(Obj, "access", access); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json(Obj, "users", users); |             field_from_json(Obj, "users", users); | ||||||
|             RESTAPI_utils::field_from_json(Obj, "roles", roles); |  | ||||||
|             field_from_json(Obj, "access", access); |             field_from_json(Obj, "access", access); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
| @@ -519,12 +471,12 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|      |      | ||||||
|     void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { |     void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "list", list); |         field_to_json(Obj, "list", list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json(Obj, "list", list); |             field_from_json(Obj, "list", list); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -532,54 +484,23 @@ namespace OpenWifi::ProvObjects { | |||||||
|         return false; |         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 { |     void Map::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"data",data); |         field_to_json( Obj,"data",data); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"creator",creator); |         field_to_json( Obj,"creator",creator); | ||||||
|         field_to_json( Obj,"visibility",visibility); |         field_to_json( Obj,"visibility",visibility); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"access",access); |         field_to_json( Obj,"access",access); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"data",data); |             field_from_json( Obj,"data",data); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"creator",creator); |             field_from_json( Obj,"creator",creator); | ||||||
|             field_from_json( Obj,"visibility",visibility); |             field_from_json( Obj,"visibility",visibility); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"access",access); |             field_from_json( Obj,"access",access); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -588,12 +509,12 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void MapList::to_json(Poco::JSON::Object &Obj) const { |     void MapList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json( Obj,"list",list); |         field_to_json( Obj,"list",list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"list",list); |             field_from_json( Obj,"list",list); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -609,7 +530,7 @@ namespace OpenWifi::ProvObjects { | |||||||
|         if(I.name.empty()) |         if(I.name.empty()) | ||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
|         if(O->has("description")) |        if(O->has("description")) | ||||||
|             I.description = O->get("description").toString(); |             I.description = O->get("description").toString(); | ||||||
|         SecurityObjects::MergeNotes(O,U,I.notes); |         SecurityObjects::MergeNotes(O,U,I.notes); | ||||||
|         SecurityObjects::NoteInfoVec N; |         SecurityObjects::NoteInfoVec N; | ||||||
| @@ -645,5 +566,4 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| } | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,9 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  | #ifndef OWPROV_RESTAPI_PROVOBJECTS_H | ||||||
|  | #define OWPROV_RESTAPI_PROVOBJECTS_H | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| @@ -284,22 +286,12 @@ namespace OpenWifi::ProvObjects { | |||||||
|         std::string     deviceConfiguration; |         std::string     deviceConfiguration; | ||||||
|         std::string     rrm; |         std::string     rrm; | ||||||
|         Types::UUID_t   managementPolicy; |         Types::UUID_t   managementPolicy; | ||||||
|         std::string     state; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     typedef std::vector<InventoryTag>      InventoryTagVec; |     typedef std::vector<InventoryTag>      InventoryTagVec; | ||||||
|  |  | ||||||
|     struct InventoryTagList { |  | ||||||
|         InventoryTagVec     taglist; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     struct Report { |     struct Report { | ||||||
|         uint64_t            snapShot=0; |         uint64_t            snapShot=0; | ||||||
|         Types::CountedMap   tenants; |         Types::CountedMap   tenants; | ||||||
| @@ -332,21 +324,16 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct UuidList { |     struct UserList { | ||||||
|         std::vector<std::string>    list; |         std::vector<std::string>    list; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     enum ACLACCESS { |  | ||||||
|         NONE, READ, MODIFY, CREATE, DELETE |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct ObjectACL { |     struct ObjectACL { | ||||||
|         UuidList        users; |         UserList        users; | ||||||
|         UuidList        roles; |         std::string     access; | ||||||
|         ACLACCESS       access = NONE; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -359,19 +346,12 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         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 { |     struct Map { | ||||||
|         ObjectInfo          info; |         ObjectInfo          info; | ||||||
|         std::string         data; |         std::string         data; | ||||||
|         std::string         entity; |         std::string         entity; | ||||||
|         std::string         creator; |         std::string         creator; | ||||||
|         VISIBILITY          visibility = PRIVATE; |         std::string         visibility; | ||||||
|         ObjectACLList       access; |         ObjectACLList       access; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
| @@ -387,4 +367,8 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); |     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); |     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //OWPROV_RESTAPI_PROVOBJECTS_H | ||||||
|   | |||||||
| @@ -54,8 +54,6 @@ namespace OpenWifi::SecurityObjects { | |||||||
|             return ADMIN; |             return ADMIN; | ||||||
|         else if (!Poco::icompare(U,"subscriber")) |         else if (!Poco::icompare(U,"subscriber")) | ||||||
|             return SUBSCRIBER; |             return SUBSCRIBER; | ||||||
|         else if (!Poco::icompare(U,"partner")) |  | ||||||
|             return PARTNER; |  | ||||||
|         else if (!Poco::icompare(U,"csr")) |         else if (!Poco::icompare(U,"csr")) | ||||||
|             return CSR; |             return CSR; | ||||||
|         else if (!Poco::icompare(U, "system")) |         else if (!Poco::icompare(U, "system")) | ||||||
| @@ -74,7 +72,6 @@ namespace OpenWifi::SecurityObjects { | |||||||
|             case ROOT: return "root"; |             case ROOT: return "root"; | ||||||
|             case ADMIN: return "admin"; |             case ADMIN: return "admin"; | ||||||
|             case SUBSCRIBER: return "subscriber"; |             case SUBSCRIBER: return "subscriber"; | ||||||
|             case PARTNER: return "partner"; |  | ||||||
|             case CSR: return "csr"; |             case CSR: return "csr"; | ||||||
|             case SYSTEM: return "system"; |             case SYSTEM: return "system"; | ||||||
|             case INSTALLER: return "installer"; |             case INSTALLER: return "installer"; | ||||||
| @@ -172,14 +169,12 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { | 	void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 	    field_to_json(Obj, "mobiles", mobiles); | 	    field_to_json(Obj, "mobiles", mobiles); | ||||||
| 	    field_to_json(Obj, "mfa", mfa); | 	    field_to_json(Obj, "mfa", mfa); | ||||||
|         field_to_json(Obj, "authenticatorSecret", authenticatorSecret); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { | 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        field_from_json(Obj, "mobiles",mobiles); | 	        field_from_json(Obj,"mobiles",mobiles); | ||||||
| 	        field_from_json(Obj, "mfa",mfa); | 	        field_from_json(Obj,"mfa",mfa); | ||||||
|             field_from_json(Obj, "authenticatorSecret", authenticatorSecret); |  | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch (...) { | 	    } catch (...) { | ||||||
|  |  | ||||||
| @@ -226,7 +221,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UserInfo::to_json(Poco::JSON::Object &Obj) const { |     void UserInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"id",id); | 		field_to_json(Obj,"Id",Id); | ||||||
| 		field_to_json(Obj,"name",name); | 		field_to_json(Obj,"name",name); | ||||||
| 		field_to_json(Obj,"description", description); | 		field_to_json(Obj,"description", description); | ||||||
| 		field_to_json(Obj,"avatar", avatar); | 		field_to_json(Obj,"avatar", avatar); | ||||||
| @@ -256,12 +251,11 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"lastPasswords",lastPasswords); | 		field_to_json(Obj,"lastPasswords",lastPasswords); | ||||||
| 		field_to_json(Obj,"oauthType",oauthType); | 		field_to_json(Obj,"oauthType",oauthType); | ||||||
| 		field_to_json(Obj,"oauthUserInfo",oauthUserInfo); | 		field_to_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||||
|         field_to_json(Obj,"modified",modified); |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
| 			field_from_json(Obj,"id",id); | 			field_from_json(Obj,"Id",Id); | ||||||
| 			field_from_json(Obj,"name",name); | 			field_from_json(Obj,"name",name); | ||||||
| 			field_from_json(Obj,"description",description); | 			field_from_json(Obj,"description",description); | ||||||
| 			field_from_json(Obj,"avatar",avatar); | 			field_from_json(Obj,"avatar",avatar); | ||||||
| @@ -271,8 +265,6 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"currentLoginURI",currentLoginURI); | 			field_from_json(Obj,"currentLoginURI",currentLoginURI); | ||||||
| 			field_from_json(Obj,"locale",locale); | 			field_from_json(Obj,"locale",locale); | ||||||
| 			field_from_json(Obj,"notes",notes); | 			field_from_json(Obj,"notes",notes); | ||||||
|             field_from_json(Obj,"location", location); |  | ||||||
|             field_from_json(Obj,"owner", owner); |  | ||||||
| 			field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString); | 			field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString); | ||||||
| 			field_from_json(Obj,"securityPolicy",securityPolicy); | 			field_from_json(Obj,"securityPolicy",securityPolicy); | ||||||
| 			field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); | 			field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); | ||||||
| @@ -291,7 +283,6 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"lastPasswords",lastPasswords); | 			field_from_json(Obj,"lastPasswords",lastPasswords); | ||||||
| 			field_from_json(Obj,"oauthType",oauthType); | 			field_from_json(Obj,"oauthType",oauthType); | ||||||
| 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | 			field_from_json(Obj,"oauthUserInfo",oauthUserInfo); | ||||||
|             field_from_json(Obj,"modified",modified); |  | ||||||
|             return true; |             return true; | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|  |  | ||||||
| @@ -500,7 +491,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"expires",expires); | 	    field_to_json(Obj,"expires",expires); | ||||||
| 	    field_to_json(Obj,"completed",completed); | 	    field_to_json(Obj,"completed",completed); | ||||||
| 	    field_to_json(Obj,"canceled",canceled); | 	    field_to_json(Obj,"canceled",canceled); | ||||||
|         field_to_json(Obj,"userAction",userAction); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { |     bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -517,86 +508,11 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	        field_from_json(Obj,"expires",expires); | 	        field_from_json(Obj,"expires",expires); | ||||||
| 	        field_from_json(Obj,"completed",completed); | 	        field_from_json(Obj,"completed",completed); | ||||||
| 	        field_from_json(Obj,"canceled",canceled); | 	        field_from_json(Obj,"canceled",canceled); | ||||||
|             field_from_json(Obj,"userAction",userAction); |  | ||||||
| 	        return true; | 	        return true; | ||||||
| 	    } catch(...) { | 	    } catch(...) { | ||||||
|  |  | ||||||
| 	    } | 	    } | ||||||
| 	    return false; | 	    return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     void Preferences::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
| 	    field_to_json(Obj,"id",id); |  | ||||||
| 	    field_to_json(Obj,"modified",modified); |  | ||||||
| 	    field_to_json(Obj,"data",data); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     bool Preferences::from_json(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(...) { |  | ||||||
|  |  | ||||||
| 	    } |  | ||||||
| 	    return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
| 	    field_to_json(Obj,"id",id); |  | ||||||
| 	    field_to_json(Obj,"type",type); |  | ||||||
| 	    field_to_json(Obj,"sms",sms); |  | ||||||
| 	    field_to_json(Obj,"email",email); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     bool SubMfaConfig::from_json(Poco::JSON::Object::Ptr &Obj) { |  | ||||||
| 	    try { |  | ||||||
| 	        field_from_json(Obj,"id",id); |  | ||||||
| 	        field_from_json(Obj,"type",type); |  | ||||||
| 	        field_from_json(Obj,"sms",sms); |  | ||||||
| 	        field_from_json(Obj,"email",email); |  | ||||||
| 	        return true; |  | ||||||
| 	    } catch(...) { |  | ||||||
|  |  | ||||||
| 	    } |  | ||||||
| 	    return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     void Token::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj,"token",token); |  | ||||||
|         field_to_json(Obj,"refreshToken",refreshToken); |  | ||||||
|         field_to_json(Obj,"tokenType",tokenType); |  | ||||||
|         field_to_json(Obj,"userName",userName); |  | ||||||
|         field_to_json(Obj,"created",created); |  | ||||||
|         field_to_json(Obj,"expires",expires); |  | ||||||
|         field_to_json(Obj,"idleTimeout",idleTimeout); |  | ||||||
|         field_to_json(Obj,"revocationDate",revocationDate); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool Token::from_json(Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj,"token",token); |  | ||||||
|             field_from_json(Obj,"refreshToken",refreshToken); |  | ||||||
|             field_from_json(Obj,"tokenType",tokenType); |  | ||||||
|             field_from_json(Obj,"userName",userName); |  | ||||||
|             field_from_json(Obj,"created",created); |  | ||||||
|             field_from_json(Obj,"expires",expires); |  | ||||||
|             field_from_json(Obj,"idleTimeout",idleTimeout); |  | ||||||
|             field_from_json(Obj,"revocationDate",revocationDate); |  | ||||||
|             return true; |  | ||||||
|         } catch(...) { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void LoginRecordInfo::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj,"sessionId",sessionId); |  | ||||||
|         field_to_json(Obj,"userId",userId); |  | ||||||
|         field_to_json(Obj,"email",email); |  | ||||||
|         field_to_json(Obj,"login",login); |  | ||||||
|         field_to_json(Obj,"logout",logout); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,303 +6,244 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRAL_RESTAPI_SECURITYOBJECTS_H | ||||||
|  | #define UCENTRAL_RESTAPI_SECURITYOBJECTS_H | ||||||
|  |  | ||||||
| #include <string> |  | ||||||
| #include "framework/OpenWifiTypes.h" |  | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "Poco/Data/LOB.h" | #include "framework/OpenWifiTypes.h" | ||||||
| #include "Poco/Data/LOBStream.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi::SecurityObjects { | ||||||
|     namespace SecurityObjects { |  | ||||||
|  |  | ||||||
|         typedef std::string USER_ID_TYPE; | 	struct AclTemplate { | ||||||
|  | 		bool Read_ = true; | ||||||
|  | 		bool ReadWrite_ = true; | ||||||
|  | 		bool ReadWriteCreate_ = true; | ||||||
|  | 		bool Delete_ = true; | ||||||
|  | 		bool PortalLogin_ = true; | ||||||
|  |  | ||||||
|         struct AclTemplate { | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool Read_ = true; | 		bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; | ||||||
|             bool ReadWrite_ = true; |  | ||||||
|             bool ReadWriteCreate_ = true; |  | ||||||
|             bool Delete_ = true; |  | ||||||
|             bool PortalLogin_ = true; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	struct WebToken { | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; | 		std::string access_token_; | ||||||
|  | 		std::string refresh_token_; | ||||||
|  | 		std::string id_token_; | ||||||
|  | 		std::string token_type_; | ||||||
|  | 		std::string username_; | ||||||
|  | 		bool userMustChangePassword=false; | ||||||
|  |         uint64_t errorCode=0; | ||||||
|  | 		uint64_t expires_in_=0; | ||||||
|  | 		uint64_t idle_timeout_=0; | ||||||
|  | 		AclTemplate acl_template_; | ||||||
|  | 		uint64_t created_=0; | ||||||
|  |  | ||||||
|         struct WebToken { | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string access_token_; | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string refresh_token_; | 	}; | ||||||
|             std::string id_token_; |  | ||||||
|             std::string token_type_; |  | ||||||
|             std::string username_; |  | ||||||
|             bool userMustChangePassword=false; |  | ||||||
|             uint64_t errorCode=0; |  | ||||||
|             uint64_t expires_in_=0; |  | ||||||
|             uint64_t idle_timeout_=0; |  | ||||||
|             AclTemplate acl_template_; |  | ||||||
|             uint64_t created_=0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |     enum USER_ROLE { | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |         UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING | ||||||
|         }; |     }; | ||||||
|  |  | ||||||
|         enum USER_ROLE { |     USER_ROLE UserTypeFromString(const std::string &U); | ||||||
|             UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER |     std::string UserTypeToString(USER_ROLE U); | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         USER_ROLE UserTypeFromString(const std::string &U); |     struct NoteInfo { | ||||||
|         std::string UserTypeToString(USER_ROLE U); | 		uint64_t created = std::time(nullptr); | ||||||
|  | 		std::string createdBy; | ||||||
|  | 		std::string note; | ||||||
|  | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::vector<NoteInfo>	NoteInfoVec; | ||||||
|  |  | ||||||
|         struct NoteInfo { | 	struct MobilePhoneNumber { | ||||||
|             uint64_t created = std::time(nullptr); | 	    std::string number; | ||||||
|             std::string createdBy; | 	    bool verified = false; | ||||||
|             std::string note; | 	    bool primary = false; | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|         typedef std::vector<NoteInfo>	NoteInfoVec; |  | ||||||
|  |  | ||||||
|         struct MobilePhoneNumber { | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string number; | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             bool verified = false; | 	}; | ||||||
|             bool primary = false; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	struct MfaAuthInfo { | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | 	    bool enabled = false; | ||||||
|         }; | 	    std::string method; | ||||||
|  |  | ||||||
|         struct MfaAuthInfo { | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool enabled = false; | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string method; | 	}; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	struct UserLoginLoginExtensions { | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | 	    std::vector<MobilePhoneNumber>  mobiles; | ||||||
|         }; | 	    struct MfaAuthInfo mfa; | ||||||
|  |  | ||||||
|         struct UserLoginLoginExtensions { | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::vector<MobilePhoneNumber>  mobiles; | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             struct MfaAuthInfo              mfa; | 	}; | ||||||
|             std::string                     authenticatorSecret; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	struct MFAChallengeRequest { | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | 	    std::string uuid; | ||||||
|         }; | 	    std::string question; | ||||||
|  | 	    std::string method; | ||||||
|  | 	    uint64_t    created = std::time(nullptr); | ||||||
|  |  | ||||||
|         struct MFAChallengeRequest { | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string uuid; | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string question; | 	}; | ||||||
|             std::string method; |  | ||||||
|             uint64_t    created = std::time(nullptr); |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |     struct MFAChallengeResponse { | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |         std::string uuid; | ||||||
|         }; |         std::string answer; | ||||||
|  |  | ||||||
|         struct MFAChallengeResponse { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string uuid; |         bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string answer; |     }; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	struct UserInfo { | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |         std::string Id; | ||||||
|         }; | 		std::string name; | ||||||
|  | 		std::string description; | ||||||
|  | 		std::string avatar; | ||||||
|  | 		std::string email; | ||||||
|  | 		bool validated = false; | ||||||
|  | 		std::string validationEmail; | ||||||
|  | 		uint64_t validationDate = 0; | ||||||
|  | 		uint64_t creationDate = 0; | ||||||
|  | 		std::string validationURI; | ||||||
|  | 		bool changePassword = false; | ||||||
|  | 		uint64_t lastLogin = 0; | ||||||
|  | 		std::string currentLoginURI; | ||||||
|  | 		uint64_t lastPasswordChange = 0; | ||||||
|  | 		uint64_t lastEmailCheck = 0; | ||||||
|  | 		bool waitingForEmailCheck = false; | ||||||
|  | 		std::string locale; | ||||||
|  | 		NoteInfoVec notes; | ||||||
|  | 		std::string location; | ||||||
|  | 		std::string owner; | ||||||
|  | 		bool suspended = false; | ||||||
|  | 		bool blackListed = false; | ||||||
|  |         USER_ROLE userRole; | ||||||
|  |         UserLoginLoginExtensions userTypeProprietaryInfo; | ||||||
|  | 		std::string securityPolicy; | ||||||
|  | 		uint64_t securityPolicyChange = 0 ; | ||||||
|  | 		std::string currentPassword; | ||||||
|  | 		Types::StringVec lastPasswords; | ||||||
|  | 		std::string oauthType; | ||||||
|  | 		std::string oauthUserInfo; | ||||||
|  |  | ||||||
|         struct UserInfo { | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string id; | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string name; | 	}; | ||||||
|             std::string description; | 	typedef std::vector<UserInfo>   UserInfoVec; | ||||||
|             std::string avatar; |  | ||||||
|             std::string email; |  | ||||||
|             bool        validated = false; |  | ||||||
|             std::string validationEmail; |  | ||||||
|             uint64_t    validationDate = 0; |  | ||||||
|             uint64_t    creationDate = 0; |  | ||||||
|             std::string validationURI; |  | ||||||
|             bool        changePassword = false; |  | ||||||
|             uint64_t    lastLogin = 0; |  | ||||||
|             std::string currentLoginURI; |  | ||||||
|             uint64_t    lastPasswordChange = 0; |  | ||||||
|             uint64_t    lastEmailCheck = 0; |  | ||||||
|             bool        waitingForEmailCheck = false; |  | ||||||
|             std::string locale; |  | ||||||
|             NoteInfoVec notes; |  | ||||||
|             std::string location; |  | ||||||
|             std::string owner; |  | ||||||
|             bool        suspended = false; |  | ||||||
|             bool        blackListed = false; |  | ||||||
|             USER_ROLE   userRole; |  | ||||||
|             UserLoginLoginExtensions userTypeProprietaryInfo; |  | ||||||
|             std::string securityPolicy; |  | ||||||
|             uint64_t    securityPolicyChange = 0 ; |  | ||||||
|             std::string currentPassword; |  | ||||||
|             OpenWifi::Types::StringVec lastPasswords; |  | ||||||
|             std::string oauthType; |  | ||||||
|             std::string oauthUserInfo; |  | ||||||
|             uint64_t    modified; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	// bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | 	bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | ||||||
|         }; | 	bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); | ||||||
|         typedef std::vector<UserInfo>   UserInfoVec; |  | ||||||
|  |  | ||||||
|         // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | 	struct InternalServiceInfo { | ||||||
|         bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); | 		std::string privateURI; | ||||||
|         bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); | 		std::string publicURI; | ||||||
|  | 		std::string token; | ||||||
|  | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::vector<InternalServiceInfo>	InternalServiceInfoVec; | ||||||
|  |  | ||||||
|         struct InternalServiceInfo { | 	struct InternalSystemServices { | ||||||
|             std::string privateURI; | 		std::string key; | ||||||
|             std::string publicURI; | 		std::string version; | ||||||
|             std::string token; | 		InternalServiceInfoVec services; | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|         }; | 	}; | ||||||
|         typedef std::vector<InternalServiceInfo>	InternalServiceInfoVec; |  | ||||||
|  |  | ||||||
|         struct InternalSystemServices { | 	struct SystemEndpoint { | ||||||
|             std::string key; | 		std::string type; | ||||||
|             std::string version; | 		uint64_t 	id = 0; | ||||||
|             InternalServiceInfoVec services; | 		std::string vendor{"OpenWiFi"}; | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 		std::string uri; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		std::string authenticationType{"internal_v1"}; | ||||||
|         }; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::vector<SystemEndpoint> SystemEndpointVec; | ||||||
|  |  | ||||||
|         struct SystemEndpoint { | 	struct SystemEndpointList { | ||||||
|             std::string type; | 		SystemEndpointVec	endpoints; | ||||||
|             uint64_t 	id = 0; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string vendor{"OpenWiFi"}; | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             std::string uri; | 	}; | ||||||
|             std::string authenticationType{"internal_v1"}; |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|         typedef std::vector<SystemEndpoint> SystemEndpointVec; |  | ||||||
|  |  | ||||||
|         struct SystemEndpointList { | 	struct UserInfoAndPolicy { | ||||||
|             SystemEndpointVec	endpoints; | 		WebToken	webtoken; | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 		UserInfo	userinfo; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         }; | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy>	UserInfoCache; | ||||||
|  |  | ||||||
|         struct UserInfoAndPolicy { | 	enum ResourceAccessType { | ||||||
|             WebToken	webtoken; | 		NONE, | ||||||
|             UserInfo	userinfo; | 		READ, | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 		MODIFY, | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		DELETE, | ||||||
|         }; | 		CREATE, | ||||||
|         typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy>	UserInfoCache; | 		TEST, | ||||||
|  | 		MOVE | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|         enum ResourceAccessType { | 	ResourceAccessType ResourceAccessTypeFromString(const std::string &s); | ||||||
|             NONE, | 	std::string ResourceAccessTypeToString(const ResourceAccessType & T); | ||||||
|             READ, |  | ||||||
|             MODIFY, |  | ||||||
|             DELETE, |  | ||||||
|             CREATE, |  | ||||||
|             TEST, |  | ||||||
|             MOVE |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         ResourceAccessType ResourceAccessTypeFromString(const std::string &s); | 	struct ProfileAction { | ||||||
|         std::string ResourceAccessTypeToString(const ResourceAccessType & T); | 		std::string resource; | ||||||
|  | 		ResourceAccessType access; | ||||||
|  | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::vector<ProfileAction>	ProfileActionVec; | ||||||
|  |  | ||||||
|         struct ProfileAction { | 	struct SecurityProfile { | ||||||
|             std::string resource; | 		uint64_t id=0; | ||||||
|             ResourceAccessType access; | 		std::string name; | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 		std::string description; | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | 		ProfileActionVec policy; | ||||||
|         }; | 		std::string role; | ||||||
|         typedef std::vector<ProfileAction>	ProfileActionVec; | 		NoteInfoVec notes; | ||||||
|  | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  | 	typedef std::vector<SecurityProfile> SecurityProfileVec; | ||||||
|  |  | ||||||
|         struct SecurityProfile { | 	struct SecurityProfileList { | ||||||
|             uint64_t id=0; | 		SecurityProfileVec profiles; | ||||||
|             std::string name; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string description; | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             ProfileActionVec policy; | 	}; | ||||||
|             std::string role; |  | ||||||
|             NoteInfoVec notes; |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|         typedef std::vector<SecurityProfile> SecurityProfileVec; |  | ||||||
|  |  | ||||||
|         struct SecurityProfileList { | 	enum LinkActions { | ||||||
|             SecurityProfileVec profiles; | 	    FORGOT_PASSWORD=1, | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; | 	    VERIFY_EMAIL | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); | 	}; | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         enum LinkActions { | 	struct ActionLink { | ||||||
|             FORGOT_PASSWORD=1, | 	    std::string         id; | ||||||
|             VERIFY_EMAIL, | 	    uint64_t            action; | ||||||
|             SUB_FORGOT_PASSWORD, | 	    std::string         userId; | ||||||
|             SUB_VERIFY_EMAIL | 	    std::string         actionTemplate; | ||||||
|         }; | 	    Types::StringPairVec variables; | ||||||
|  | 	    std::string         locale; | ||||||
|  | 	    std::string         message; | ||||||
|  | 	    uint64_t            sent=0; | ||||||
|  | 	    uint64_t            created=std::time(nullptr); | ||||||
|  | 	    uint64_t            expires=0; | ||||||
|  | 	    uint64_t            completed=0; | ||||||
|  | 	    uint64_t            canceled=0; | ||||||
|  |  | ||||||
|         struct ActionLink { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string         id; | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|             uint64_t            action; | 	}; | ||||||
|             std::string         userId; |  | ||||||
|             std::string         actionTemplate; |  | ||||||
|             Types::StringPairVec variables; |  | ||||||
|             std::string         locale; |  | ||||||
|             std::string         message; |  | ||||||
|             uint64_t            sent=0; |  | ||||||
|             uint64_t            created=std::time(nullptr); |  | ||||||
|             uint64_t            expires=0; |  | ||||||
|             uint64_t            completed=0; |  | ||||||
|             uint64_t            canceled=0; |  | ||||||
|             bool                userAction=true; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct Preferences { |  | ||||||
|             std::string                         id; |  | ||||||
|             uint64_t                            modified; |  | ||||||
|             Types::StringPairVec                data; |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct SubMfaConfig { |  | ||||||
|             std::string                         id; |  | ||||||
|             std::string                         type; |  | ||||||
|             std::string                         sms; |  | ||||||
|             std::string                         email; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct Token { |  | ||||||
|             std::string         token; |  | ||||||
|             std::string         refreshToken; |  | ||||||
|             std::string         tokenType; |  | ||||||
|             std::string         userName; |  | ||||||
|             uint64_t            created=0; |  | ||||||
|             uint64_t            expires=0; |  | ||||||
|             uint64_t            idleTimeout=0; |  | ||||||
|             uint64_t            revocationDate=0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct Avatar { |  | ||||||
|             std::string             id; |  | ||||||
|             std::string             type; |  | ||||||
|             uint64_t                created=0; |  | ||||||
|             std::string             name; |  | ||||||
|             Poco::Data::LOB<char>   avatar; |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         struct LoginRecordInfo { |  | ||||||
|             std::string sessionId; |  | ||||||
|             std::string userId; |  | ||||||
|             std::string email; |  | ||||||
|             uint64_t    login=0; |  | ||||||
|             uint64_t    logout=0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //UCENTRAL_RESTAPI_SECURITYOBJECTS_H | ||||||
| @@ -1,547 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-27. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "RESTAPI_SubObjects.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| using OpenWifi::RESTAPI_utils::field_to_json; |  | ||||||
| using OpenWifi::RESTAPI_utils::field_from_json; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace OpenWifi::SubObjects { |  | ||||||
|  |  | ||||||
|     void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "enableLEDS", enableLEDS); |  | ||||||
|         field_to_json(Obj, "type", type); |  | ||||||
|         field_to_json(Obj, "subnet", subnet); |  | ||||||
|         field_to_json(Obj, "subnetMask", subnetMask); |  | ||||||
|         field_to_json(Obj, "startIP", startIP); |  | ||||||
|         field_to_json(Obj, "endIP", endIP); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|         field_to_json(Obj, "subnetV6", subnetV6); |  | ||||||
|         field_to_json(Obj, "subnetMaskV6", subnetMaskV6); |  | ||||||
|         field_to_json(Obj, "startIPV6", startIPV6); |  | ||||||
|         field_to_json(Obj, "endIPV6", endIPV6); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool HomeDeviceMode::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "enableLEDS", enableLEDS); |  | ||||||
|             field_from_json(Obj, "type", type); |  | ||||||
|             field_from_json(Obj, "subnet", subnet); |  | ||||||
|             field_from_json(Obj, "subnetMask", subnetMask); |  | ||||||
|             field_from_json(Obj, "startIP", startIP); |  | ||||||
|             field_from_json(Obj, "endIP", endIP); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             field_from_json(Obj, "subnetV6", subnetV6); |  | ||||||
|             field_from_json(Obj, "subnetMaskV6", subnetMaskV6); |  | ||||||
|             field_from_json(Obj, "startIPV6", startIPV6); |  | ||||||
|             field_from_json(Obj, "endIPV6", endIPV6); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPReservation::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "nickname", nickname); |  | ||||||
|         field_to_json(Obj, "ipAddress", ipAddress); |  | ||||||
|         field_to_json(Obj, "macAddress", macAddress); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool IPReservation::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "nickname", nickname); |  | ||||||
|             field_from_json(Obj, "ipAddress", ipAddress); |  | ||||||
|             field_from_json(Obj, "macAddress", macAddress); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void IPReservationList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "id", id); |  | ||||||
|         field_to_json(Obj, "reservations", reservations); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool IPReservationList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "id", id); |  | ||||||
|             field_from_json(Obj, "reservations", reservations); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void DnsConfiguration::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "ISP", ISP); |  | ||||||
|         field_to_json(Obj, "custom", custom); |  | ||||||
|         field_to_json(Obj, "primary", primary); |  | ||||||
|         field_to_json(Obj, "secondary", secondary); |  | ||||||
|         field_to_json(Obj, "primaryV6", primaryV6); |  | ||||||
|         field_to_json(Obj, "secondaryV6", secondaryV6); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool DnsConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "ISP", ISP); |  | ||||||
|             field_from_json(Obj, "custom", custom); |  | ||||||
|             field_from_json(Obj, "primary", primary); |  | ||||||
|             field_from_json(Obj, "secondary", secondary); |  | ||||||
|             field_from_json(Obj, "primaryV6", primaryV6); |  | ||||||
|             field_from_json(Obj, "secondaryV6", secondaryV6); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void InternetConnection::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "type", type); |  | ||||||
|         field_to_json(Obj, "username", username); |  | ||||||
|         field_to_json(Obj, "password", password); |  | ||||||
|         field_to_json(Obj, "ipAddress", ipAddress); |  | ||||||
|         field_to_json(Obj, "subnetMask", subnetMask); |  | ||||||
|         field_to_json(Obj, "defaultGateway", defaultGateway); |  | ||||||
|         field_to_json(Obj, "sendHostname", sendHostname); |  | ||||||
|         field_to_json(Obj, "primaryDns", primaryDns); |  | ||||||
|         field_to_json(Obj, "secondaryDns", secondaryDns); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|         field_to_json(Obj, "ipV6Support", ipV6Support); |  | ||||||
|         field_to_json(Obj, "ipAddressV6", ipAddressV6); |  | ||||||
|         field_to_json(Obj, "subnetMaskV6", subnetMaskV6); |  | ||||||
|         field_to_json(Obj, "defaultGatewayV6", defaultGatewayV6); |  | ||||||
|         field_to_json(Obj, "primaryDnsV6", primaryDnsV6); |  | ||||||
|         field_to_json(Obj, "secondaryDnsV6", secondaryDnsV6); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool InternetConnection::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "type", type); |  | ||||||
|             field_from_json(Obj, "username", username); |  | ||||||
|             field_from_json(Obj, "password", password); |  | ||||||
|             field_from_json(Obj, "ipAddress", ipAddress); |  | ||||||
|             field_from_json(Obj, "subnetMask", subnetMask); |  | ||||||
|             field_from_json(Obj, "defaultGateway", defaultGateway); |  | ||||||
|             field_from_json(Obj, "sendHostname", sendHostname); |  | ||||||
|             field_from_json(Obj, "primaryDns", primaryDns); |  | ||||||
|             field_from_json(Obj, "secondaryDns", secondaryDns); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             field_from_json(Obj, "ipV6Support", ipV6Support); |  | ||||||
|             field_from_json(Obj, "ipAddressV6", ipAddressV6); |  | ||||||
|             field_from_json(Obj, "subnetMaskV6", subnetMaskV6); |  | ||||||
|             field_from_json(Obj, "defaultGatewayV6", defaultGatewayV6); |  | ||||||
|             field_from_json(Obj, "primaryDnsV6", primaryDnsV6); |  | ||||||
|             field_from_json(Obj, "secondaryDnsV6", secondaryDnsV6); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void WifiNetwork::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "type", type); |  | ||||||
|         field_to_json(Obj, "name", name); |  | ||||||
|         field_to_json(Obj, "password", password); |  | ||||||
|         field_to_json(Obj, "encryption", encryption); |  | ||||||
|         field_to_json(Obj, "bands", bands); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool WifiNetwork::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "type", type); |  | ||||||
|             field_from_json(Obj, "name", name); |  | ||||||
|             field_from_json(Obj, "password", password); |  | ||||||
|             field_from_json(Obj, "encryption", encryption); |  | ||||||
|             field_from_json(Obj, "bands", bands); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void WifiNetworkList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "wifiNetworks", wifiNetworks); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool WifiNetworkList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "wifiNetworks", wifiNetworks); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AccessTime::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "day", day); |  | ||||||
|         field_to_json(Obj, "rangeList", rangeList); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AccessTime::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "day", day); |  | ||||||
|             field_from_json(Obj, "rangeList", rangeList); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AccessTimes::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "schedule", schedule); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AccessTimes::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "schedule", schedule); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "name", name); |  | ||||||
|         field_to_json(Obj, "description", description); |  | ||||||
|         field_to_json(Obj, "macAddress", macAddress); |  | ||||||
|         field_to_json(Obj, "manufacturer", manufacturer); |  | ||||||
|         field_to_json(Obj, "firstContact", firstContact); |  | ||||||
|         field_to_json(Obj, "lastContact", lastContact); |  | ||||||
|         field_to_json(Obj, "group", group); |  | ||||||
|         field_to_json(Obj, "icon", icon); |  | ||||||
|         field_to_json(Obj, "suspended", suspended); |  | ||||||
|         field_to_json(Obj, "ip", ip); |  | ||||||
|         field_to_json(Obj, "schedule", schedule); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "name", name); |  | ||||||
|             field_from_json(Obj, "description", description); |  | ||||||
|             field_from_json(Obj, "macAddress", macAddress); |  | ||||||
|             field_from_json(Obj, "manufacturer", manufacturer); |  | ||||||
|             field_from_json(Obj, "firstContact", firstContact); |  | ||||||
|             field_from_json(Obj, "lastContact", lastContact); |  | ||||||
|             field_from_json(Obj, "group", group); |  | ||||||
|             field_from_json(Obj, "icon", icon); |  | ||||||
|             field_from_json(Obj, "suspended", suspended); |  | ||||||
|             field_from_json(Obj, "ip", ip); |  | ||||||
|             field_from_json(Obj, "schedule", schedule); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "devices", devices); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "devices", devices); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void Association::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "name", name); |  | ||||||
|         field_to_json(Obj, "ssid", ssid); |  | ||||||
|         field_to_json(Obj, "macAddress", macAddress); |  | ||||||
|         field_to_json(Obj, "rssi", rssi); |  | ||||||
|         field_to_json(Obj, "power", power); |  | ||||||
|         field_to_json(Obj, "ipv4", ipv4); |  | ||||||
|         field_to_json(Obj, "ipv6", ipv6); |  | ||||||
|         field_to_json(Obj, "tx", tx); |  | ||||||
|         field_to_json(Obj, "rx", rx); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "name", name); |  | ||||||
|             field_from_json(Obj, "ssid", ssid); |  | ||||||
|             field_from_json(Obj, "macAddress", macAddress); |  | ||||||
|             field_from_json(Obj, "rssi", rssi); |  | ||||||
|             field_from_json(Obj, "power", power); |  | ||||||
|             field_from_json(Obj, "ipv4", ipv4); |  | ||||||
|             field_from_json(Obj, "ipv6", ipv6); |  | ||||||
|             field_from_json(Obj, "tx", tx); |  | ||||||
|             field_from_json(Obj, "rx", rx); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AssociationList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "associations", associations); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AssociationList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "associations", associations); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void Client::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "macAddress", macAddress); |  | ||||||
|         field_to_json(Obj, "speed", speed); |  | ||||||
|         field_to_json(Obj, "mode", mode); |  | ||||||
|         field_to_json(Obj, "ipv4", ipv4); |  | ||||||
|         field_to_json(Obj, "ipv6", ipv6); |  | ||||||
|         field_to_json(Obj, "tx", tx); |  | ||||||
|         field_to_json(Obj, "rx", rx); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "macAddress", macAddress); |  | ||||||
|             field_from_json(Obj, "speed", speed); |  | ||||||
|             field_from_json(Obj, "mode", mode); |  | ||||||
|             field_from_json(Obj, "ipv4", ipv4); |  | ||||||
|             field_from_json(Obj, "ipv6", ipv6); |  | ||||||
|             field_from_json(Obj, "tx", tx); |  | ||||||
|             field_from_json(Obj, "rx", rx); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void ClientList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "clients", clients); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool ClientList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "clients", clients); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void Location::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "buildingName", buildingName); |  | ||||||
|         field_to_json(Obj, "addressLines", addressLines); |  | ||||||
|         field_to_json(Obj, "city", city); |  | ||||||
|         field_to_json(Obj, "state", state); |  | ||||||
|         field_to_json(Obj, "postal", postal); |  | ||||||
|         field_to_json(Obj, "country", country); |  | ||||||
|         field_to_json(Obj, "phones", phones); |  | ||||||
|         field_to_json(Obj, "mobiles", mobiles); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "buildingName", buildingName); |  | ||||||
|             field_from_json(Obj, "addressLines", addressLines); |  | ||||||
|             field_from_json(Obj, "city", city); |  | ||||||
|             field_from_json(Obj, "state", state); |  | ||||||
|             field_from_json(Obj, "postal", postal); |  | ||||||
|             field_from_json(Obj, "country", country); |  | ||||||
|             field_from_json(Obj, "phones", phones); |  | ||||||
|             field_from_json(Obj, "mobiles", mobiles); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RadioHE::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "multipleBSSID", multipleBSSID); |  | ||||||
|         field_to_json(Obj, "ema", ema); |  | ||||||
|         field_to_json(Obj, "bssColor", bssColor); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool RadioHE::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "multipleBSSID", multipleBSSID); |  | ||||||
|             field_from_json(Obj, "ema", ema); |  | ||||||
|             field_from_json(Obj, "bssColor", bssColor); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RadioRates::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "beacon", beacon); |  | ||||||
|         field_to_json(Obj, "multicast", multicast); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool RadioRates::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "beacon", beacon); |  | ||||||
|             field_from_json(Obj, "multicast", multicast); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void RadioInformation::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "band", band); |  | ||||||
|         field_to_json(Obj, "bandwidth", bandwidth); |  | ||||||
|         field_to_json(Obj, "channel", channel); |  | ||||||
|         field_to_json(Obj, "country", country); |  | ||||||
|         field_to_json(Obj, "channelMode", channelMode); |  | ||||||
|         field_to_json(Obj, "channelWidth", channelWidth); |  | ||||||
|         field_to_json(Obj, "requireMode", requireMode); |  | ||||||
|         field_to_json(Obj, "txpower", txpower); |  | ||||||
|         field_to_json(Obj, "legacyRates", legacyRates); |  | ||||||
|         field_to_json(Obj, "beaconInterval", beaconInterval); |  | ||||||
|         field_to_json(Obj, "dtimPeriod", dtimPeriod); |  | ||||||
|         field_to_json(Obj, "maximumClients", maximumClients); |  | ||||||
|         field_to_json(Obj, "rates", rates); |  | ||||||
|         field_to_json(Obj, "he", he); |  | ||||||
|         field_to_json(Obj, "rawInfo", rawInfo); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool RadioInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "band", band); |  | ||||||
|             field_from_json(Obj, "bandwidth", bandwidth); |  | ||||||
|             field_from_json(Obj, "channel", channel); |  | ||||||
|             field_from_json(Obj, "country", country); |  | ||||||
|             field_from_json(Obj, "channelMode", channelMode); |  | ||||||
|             field_from_json(Obj, "channelWidth", channelWidth); |  | ||||||
|             field_from_json(Obj, "requireMode", requireMode); |  | ||||||
|             field_from_json(Obj, "txpower", txpower); |  | ||||||
|             field_from_json(Obj, "legacyRates", legacyRates); |  | ||||||
|             field_from_json(Obj, "beaconInterval", beaconInterval); |  | ||||||
|             field_from_json(Obj, "dtimPeriod", dtimPeriod); |  | ||||||
|             field_from_json(Obj, "maximumClients", maximumClients); |  | ||||||
|             field_from_json(Obj, "rates", rates); |  | ||||||
|             field_from_json(Obj, "he", he); |  | ||||||
|             field_from_json(Obj, "rawInfo", rawInfo); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AccessPoint::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "id", id); |  | ||||||
|         field_to_json(Obj, "macAddress", macAddress); |  | ||||||
|         field_to_json(Obj, "name", name); |  | ||||||
|         field_to_json(Obj, "deviceType", deviceType); |  | ||||||
|         field_to_json(Obj, "subscriberDevices", subscriberDevices); |  | ||||||
|         field_to_json(Obj, "ipReservations", ipReservations); |  | ||||||
|         field_to_json(Obj, "address", address); |  | ||||||
|         field_to_json(Obj, "wifiNetworks", wifiNetworks); |  | ||||||
|         field_to_json(Obj, "internetConnection", internetConnection); |  | ||||||
|         field_to_json(Obj, "deviceMode", deviceMode); |  | ||||||
|         field_to_json(Obj, "dnsConfiguration", dnsConfiguration); |  | ||||||
|         field_to_json(Obj, "radios", radios); |  | ||||||
|         field_to_json(Obj, "automaticUpgrade", automaticUpgrade); |  | ||||||
|         field_to_json(Obj, "configurationUUID", configurationUUID); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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, "name", name); |  | ||||||
|             field_from_json(Obj, "deviceType", deviceType); |  | ||||||
|             field_from_json(Obj, "subscriberDevices", subscriberDevices); |  | ||||||
|             field_from_json(Obj, "ipReservations", ipReservations); |  | ||||||
|             field_from_json(Obj, "address", address); |  | ||||||
|             field_from_json(Obj, "wifiNetworks", wifiNetworks); |  | ||||||
|             field_from_json(Obj, "internetConnection", internetConnection); |  | ||||||
|             field_from_json(Obj, "deviceMode", deviceMode); |  | ||||||
|             field_from_json(Obj, "dnsConfiguration", dnsConfiguration); |  | ||||||
|             field_from_json(Obj, "radios", radios); |  | ||||||
|             field_from_json(Obj, "automaticUpgrade", automaticUpgrade); |  | ||||||
|             field_from_json(Obj, "configurationUUID", configurationUUID); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void AccessPointList::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "list", list); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AccessPointList::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "list", list); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void SubscriberInfo::to_json(Poco::JSON::Object &Obj) const { |  | ||||||
|         field_to_json(Obj, "id", id); |  | ||||||
|         field_to_json(Obj, "userId", userId); |  | ||||||
|         field_to_json(Obj, "firstName", firstName); |  | ||||||
|         field_to_json(Obj, "initials", initials); |  | ||||||
|         field_to_json(Obj, "lastName", lastName); |  | ||||||
|         field_to_json(Obj, "phoneNumber", phoneNumber); |  | ||||||
|         field_to_json(Obj, "secondaryEmail", secondaryEmail); |  | ||||||
|         field_to_json(Obj, "accessPoints", accessPoints); |  | ||||||
|         field_to_json(Obj, "serviceAddress", serviceAddress); |  | ||||||
|         field_to_json(Obj, "billingAddress", billingAddress); |  | ||||||
|         field_to_json(Obj, "created", created); |  | ||||||
|         field_to_json(Obj, "modified", modified); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool SubscriberInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { |  | ||||||
|         try { |  | ||||||
|             field_from_json(Obj, "id", id); |  | ||||||
|             field_from_json(Obj, "userId", userId); |  | ||||||
|             field_from_json(Obj, "firstName", firstName); |  | ||||||
|             field_from_json(Obj, "initials", initials); |  | ||||||
|             field_from_json(Obj, "lastName", lastName); |  | ||||||
|             field_from_json(Obj, "phoneNumber", phoneNumber); |  | ||||||
|             field_from_json(Obj, "secondaryEmail", secondaryEmail); |  | ||||||
|             field_from_json(Obj, "accessPoints", accessPoints); |  | ||||||
|             field_from_json(Obj, "serviceAddress", serviceAddress); |  | ||||||
|             field_from_json(Obj, "billingAddress", billingAddress); |  | ||||||
|             field_from_json(Obj, "created", created); |  | ||||||
|             field_from_json(Obj, "modified", modified); |  | ||||||
|             return true; |  | ||||||
|         } catch (...) { |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,293 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-27. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #ifndef OWSUB_RESTAPI_SUBOBJECTS_H |  | ||||||
| #define OWSUB_RESTAPI_SUBOBJECTS_H |  | ||||||
|  |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| #include "Poco/JSON/Object.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi::SubObjects { |  | ||||||
|  |  | ||||||
|     struct HomeDeviceMode { |  | ||||||
|         bool            enableLEDS = true; |  | ||||||
|         std::string     type;       // bridge, manual, automatic |  | ||||||
|         std::string     subnet; |  | ||||||
|         std::string     subnetMask; |  | ||||||
|         std::string     startIP; |  | ||||||
|         std::string     endIP; |  | ||||||
|         uint64_t        created = 0 ; |  | ||||||
|         uint64_t        modified = 0 ; |  | ||||||
|         std::string     subnetV6; |  | ||||||
|         int             subnetMaskV6=0; |  | ||||||
|         std::string     startIPV6; |  | ||||||
|         std::string     endIPV6; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct IPReservation  { |  | ||||||
|         std::string     nickname; |  | ||||||
|         std::string     ipAddress; |  | ||||||
|         std::string     macAddress; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct IPReservationList { |  | ||||||
|         std::string                 id; |  | ||||||
|         std::vector<IPReservation>  reservations; |  | ||||||
|         uint64_t created = 0 ; |  | ||||||
|         uint64_t modified = 0 ; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct DnsConfiguration { |  | ||||||
|         bool            ISP=false; |  | ||||||
|         bool            custom=false; |  | ||||||
|         std::string     primary; |  | ||||||
|         std::string     secondary; |  | ||||||
|         std::string     primaryV6; |  | ||||||
|         std::string     secondaryV6; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct InternetConnection { |  | ||||||
|         std::string     type; // automatic, pppoe, manual |  | ||||||
|         std::string     username; |  | ||||||
|         std::string     password; |  | ||||||
|         std::string     ipAddress; |  | ||||||
|         std::string     subnetMask; |  | ||||||
|         std::string     defaultGateway; |  | ||||||
|         bool            sendHostname = true; |  | ||||||
|         std::string     primaryDns; |  | ||||||
|         std::string     secondaryDns; |  | ||||||
|         uint64_t        created=0; |  | ||||||
|         uint64_t        modified=0; |  | ||||||
|         bool            ipV6Support=false; |  | ||||||
|         std::string     ipAddressV6; |  | ||||||
|         int             subnetMaskV6=0; |  | ||||||
|         std::string     defaultGatewayV6; |  | ||||||
|         std::string     primaryDnsV6; |  | ||||||
|         std::string     secondaryDnsV6; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct WifiNetwork { |  | ||||||
|         std::string     type;       // main, guest |  | ||||||
|         std::string     name; |  | ||||||
|         std::string     password; |  | ||||||
|         std::string     encryption; |  | ||||||
|         std::vector<std::string>    bands; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct WifiNetworkList { |  | ||||||
|         std::vector<WifiNetwork>    wifiNetworks; |  | ||||||
|         uint64_t                    created=0; |  | ||||||
|         uint64_t                    modified=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct AccessTime { |  | ||||||
|         std::string day; |  | ||||||
|         std::vector<std::string>    rangeList; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct AccessTimes { |  | ||||||
|         std::vector<AccessTime> schedule; |  | ||||||
|         uint64_t        created=0; |  | ||||||
|         uint64_t        modified=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct SubscriberDevice { |  | ||||||
|         std::string     name; |  | ||||||
|         std::string     description; |  | ||||||
|         std::string     macAddress; |  | ||||||
|         std::string     manufacturer; |  | ||||||
|         uint64_t        firstContact=0; |  | ||||||
|         uint64_t        lastContact=0; |  | ||||||
|         std::string     group; |  | ||||||
|         std::string     icon; |  | ||||||
|         bool            suspended=false; |  | ||||||
|         std::string     ip; |  | ||||||
|         std::vector<AccessTimes>    schedule; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct SubscriberDeviceList { |  | ||||||
|         std::vector<SubscriberDevice>   devices; |  | ||||||
|         uint64_t        created=0; |  | ||||||
|         uint64_t        modified=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct Association { |  | ||||||
|         std::string     name; |  | ||||||
|         std::string     ssid; |  | ||||||
|         std::string     macAddress; |  | ||||||
|         int             rssi=0; |  | ||||||
|         int             power=0; |  | ||||||
|         std::string     ipv4; |  | ||||||
|         std::string     ipv6; |  | ||||||
|         uint64_t        tx=0; |  | ||||||
|         uint64_t        rx=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct AssociationList { |  | ||||||
|         std::vector<Association>    associations; |  | ||||||
|         uint64_t        created=0; |  | ||||||
|         uint64_t        modified=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct Client { |  | ||||||
|         std::string     macAddress; |  | ||||||
|         std::string     speed; |  | ||||||
|         std::string     mode; |  | ||||||
|         std::string     ipv4; |  | ||||||
|         std::string     ipv6; |  | ||||||
|         uint64_t        tx=0; |  | ||||||
|         uint64_t        rx=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct ClientList { |  | ||||||
|         std::vector<Client> clients; |  | ||||||
|         uint64_t        created=0; |  | ||||||
|         uint64_t        modified=0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct Location { |  | ||||||
|         std::string                 buildingName; |  | ||||||
|         std::vector<std::string>    addressLines; |  | ||||||
|         std::string                 city; |  | ||||||
|         std::string                 state; |  | ||||||
|         std::string                 postal; |  | ||||||
|         std::string                 country; |  | ||||||
|         std::vector<std::string>    phones; |  | ||||||
|         std::vector<std::string>    mobiles; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct RadioHE { |  | ||||||
|         bool                        multipleBSSID = false; |  | ||||||
|         bool                        ema = false; |  | ||||||
|         uint64_t                    bssColor = 64; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct RadioRates { |  | ||||||
|         uint64_t                    beacon = 6000; |  | ||||||
|         uint64_t                    multicast = 24000; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct RadioInformation { |  | ||||||
|         std::string             band; |  | ||||||
|         uint64_t                bandwidth; |  | ||||||
|         uint64_t                channel = 0 ; |  | ||||||
|         std::string             country; |  | ||||||
|         std::string             channelMode{"HE"}; |  | ||||||
|         uint64_t                channelWidth = 80; |  | ||||||
|         std::string             requireMode; |  | ||||||
|         uint64_t                txpower=0; |  | ||||||
|         bool                    legacyRates = false; |  | ||||||
|         uint64_t                beaconInterval = 100; |  | ||||||
|         uint64_t                dtimPeriod = 2; |  | ||||||
|         uint64_t                maximumClients = 64; |  | ||||||
|         RadioRates              rates; |  | ||||||
|         RadioHE                 he; |  | ||||||
|         std::vector<std::string>    rawInfo; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct AccessPoint { |  | ||||||
|         std::string                 id; |  | ||||||
|         std::string                 macAddress; |  | ||||||
|         std::string                 name; |  | ||||||
|         std::string                 deviceType; |  | ||||||
|         SubscriberDeviceList        subscriberDevices; |  | ||||||
|         IPReservationList           ipReservations; |  | ||||||
|         Location                    address; |  | ||||||
|         WifiNetworkList             wifiNetworks; |  | ||||||
|         InternetConnection          internetConnection; |  | ||||||
|         HomeDeviceMode              deviceMode; |  | ||||||
|         DnsConfiguration            dnsConfiguration; |  | ||||||
|         std::vector<RadioInformation>   radios; |  | ||||||
|         bool                        automaticUpgrade = true; |  | ||||||
|         std::string                 configurationUUID; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct AccessPointList { |  | ||||||
|         std::vector<AccessPoint>   list; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct SubscriberInfo { |  | ||||||
|         std::string                 id; |  | ||||||
|         std::string                 userId; |  | ||||||
|         std::string                 firstName; |  | ||||||
|         std::string                 initials; |  | ||||||
|         std::string                 lastName; |  | ||||||
|         std::string                 phoneNumber; |  | ||||||
|         std::string                 secondaryEmail; |  | ||||||
|         AccessPointList             accessPoints; |  | ||||||
|         Location                    serviceAddress; |  | ||||||
|         Location                    billingAddress; |  | ||||||
|         uint64_t                    created = 0; |  | ||||||
|         uint64_t                    modified = 0; |  | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif //OWSUB_RESTAPI_SUBOBJECTS_H |  | ||||||
| @@ -20,13 +20,12 @@ namespace OpenWifi { | |||||||
|         if(Enabled_) { |         if(Enabled_) { | ||||||
|             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); |             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); | ||||||
|             if(Provider_=="aws") { |             if(Provider_=="aws") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger()); |                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); | ||||||
|             } else if(Provider_=="twilio") { |             } else if(Provider_=="twilio") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger()); |                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); | ||||||
|             } |             } | ||||||
|             Enabled_ = ProviderImpl_->Initialize(); |             Enabled_ = ProviderImpl_->Initialize(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -77,7 +76,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { |     bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { | ||||||
|         if(!Enabled_) { |         if(!Enabled_) { | ||||||
|             Logger().information("SMS has not been enabled. Messages cannot be sent."); |             Logger_.information("SMS has not been enabled. Messages cannot be sent."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         return ProviderImpl_->Send(PhoneNumber,Message); |         return ProviderImpl_->Send(PhoneNumber,Message); | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ namespace OpenWifi { | |||||||
|         Region_ = MicroService::instance().ConfigGetString("smssender.aws.region",""); |         Region_ = MicroService::instance().ConfigGetString("smssender.aws.region",""); | ||||||
|  |  | ||||||
|         if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) { |         if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) { | ||||||
|             Logger().debug("SMSSender is disabled. Please provide key, secret, and region."); |             Logger_.debug("SMSSender is disabled. Please provide key, secret, and region."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         Running_=true; |         Running_=true; | ||||||
| @@ -51,16 +51,16 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             auto psms_out = sns.Publish(psms_req); |             auto psms_out = sns.Publish(psms_req); | ||||||
|             if (psms_out.IsSuccess()) { |             if (psms_out.IsSuccess()) { | ||||||
|                 Logger().debug(Poco::format("SMS sent to %s",PhoneNumber)); |                 Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber)); | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|             std::string ErrMsg{psms_out.GetError().GetMessage()}; |             std::string ErrMsg{psms_out.GetError().GetMessage()}; | ||||||
|             Logger().debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); |             Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); | ||||||
|             return false; |             return false; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
|         } |         } | ||||||
|         Logger().debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); |         Logger_.debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ namespace OpenWifi { | |||||||
|         bool Stop() final ; |         bool Stop() final ; | ||||||
|         bool Send(const std::string &Number, const std::string &Message) final; |         bool Send(const std::string &Number, const std::string &Message) final; | ||||||
|         bool Running() final; |         bool Running() final; | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|     private: |     private: | ||||||
|         bool                                Running_=false; |         bool                                Running_=false; | ||||||
|         Poco::Logger                        &Logger_; |         Poco::Logger                        &Logger_; | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ namespace OpenWifi { | |||||||
|         PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); |         PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); | ||||||
|  |  | ||||||
|         if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { |         if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { | ||||||
|             Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); |             Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         Running_=true; |         Running_=true; | ||||||
| @@ -64,12 +64,12 @@ namespace OpenWifi { | |||||||
|         std::istream& rs = session.receiveResponse(res); |         std::istream& rs = session.receiveResponse(res); | ||||||
|  |  | ||||||
|         if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { |         if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||||
|             Logger().information(Poco::format("Message sent to %s", PhoneNumber)); |             Logger_.information(Poco::format("Message sent to %s", PhoneNumber)); | ||||||
|             return true; |             return true; | ||||||
|         } else { |         } else { | ||||||
|             std::ostringstream os; |             std::ostringstream os; | ||||||
|             Poco::StreamCopier::copyStream(rs,os); |             Poco::StreamCopier::copyStream(rs,os); | ||||||
|             Logger().information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str())); |             Logger_.information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str())); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ namespace OpenWifi { | |||||||
|         bool Stop() final ; |         bool Stop() final ; | ||||||
|         bool Send(const std::string &Number, const std::string &Message) final; |         bool Send(const std::string &Number, const std::string &Message) final; | ||||||
|         bool Running() final; |         bool Running() final; | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|     private: |     private: | ||||||
|         bool                                Running_=false; |         bool                                Running_=false; | ||||||
|         Poco::Logger                        &Logger_; |         Poco::Logger                        &Logger_; | ||||||
|   | |||||||
| @@ -49,7 +49,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void SMTPMailerService::reinitialize(Poco::Util::Application &self) { |     void SMTPMailerService::reinitialize(Poco::Util::Application &self) { | ||||||
|         MicroService::instance().LoadConfigurationFile(); |         MicroService::instance().LoadConfigurationFile(); | ||||||
|         Logger().information("Reinitializing."); |         Logger_.information("Reinitializing."); | ||||||
|         LoadMyConfig(); |         LoadMyConfig(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -83,14 +83,14 @@ namespace OpenWifi { | |||||||
|                 uint64_t Now = std::time(nullptr); |                 uint64_t Now = std::time(nullptr); | ||||||
|                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { |                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { | ||||||
|                     if (SendIt(*i)) { |                     if (SendIt(*i)) { | ||||||
|                         Logger().information(Poco::format("Attempting to deliver for mail '%s'.", Recipient)); |                         Logger_.information(Poco::format("Attempting to deliver for mail '%s'.", Recipient)); | ||||||
|                         i = Messages_.erase(i); |                         i = Messages_.erase(i); | ||||||
|                     } else { |                     } else { | ||||||
|                         i->LastTry = Now; |                         i->LastTry = Now; | ||||||
|                         ++i; |                         ++i; | ||||||
|                     } |                     } | ||||||
|                 } else if ((Now-i->Posted)>MailAbandon_) { |                 } else if ((Now-i->Posted)>MailAbandon_) { | ||||||
|                     Logger().information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient)); |                     Logger_.information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient)); | ||||||
|                     i = Messages_.erase(i); |                     i = Messages_.erase(i); | ||||||
|                 } else { |                 } else { | ||||||
|                     ++i; |                     ++i; | ||||||
| @@ -121,7 +121,7 @@ namespace OpenWifi { | |||||||
|                 TheSender = Sender_ ; |                 TheSender = Sender_ ; | ||||||
|             } |             } | ||||||
|             Message.setSender( TheSender ); |             Message.setSender( TheSender ); | ||||||
|             Logger().information(Poco::format("Sending message to:%s from %s",Recipient,TheSender)); |             Logger_.information(Poco::format("Sending message to:%s from %s",Recipient,TheSender)); | ||||||
|             Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); |             Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); |             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||||
|  |  | ||||||
| @@ -145,7 +145,7 @@ namespace OpenWifi { | |||||||
|                     Poco::StreamCopier::copyStream(IF, OS); |                     Poco::StreamCopier::copyStream(IF, OS); | ||||||
|                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); |                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||||
|                 } catch (...) { |                 } catch (...) { | ||||||
|                     Logger().warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); |                     Logger_.warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -172,10 +172,10 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|         catch (const Poco::Exception& E) |         catch (const Poco::Exception& E) | ||||||
|         { |         { | ||||||
|             Logger().log(E); |             Logger_.log(E); | ||||||
|         } |         } | ||||||
|         catch (const std::exception &E) { |         catch (const std::exception &E) { | ||||||
|             Logger().warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what())); |             Logger_.warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what())); | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,37 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-12-28. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "StorageService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     namespace SpecialUserHelpers { |  | ||||||
|         static inline std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"}; |  | ||||||
|  |  | ||||||
|         inline bool InitializeDefaultUser() { |  | ||||||
|             SecurityObjects::UserInfo U; |  | ||||||
|             bool DefaultUserCreated = false; |  | ||||||
|  |  | ||||||
|             AppServiceRegistry().Get("defaultusercreated", DefaultUserCreated); |  | ||||||
|             if (!StorageService()->UserDB().GetUserById(NewDefaultUseridStockUUID, U) && !DefaultUserCreated) { |  | ||||||
|                 U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password", ""); |  | ||||||
|                 U.lastPasswords.push_back(U.currentPassword); |  | ||||||
|                 U.email = MicroService::instance().ConfigGetString("authentication.default.username", ""); |  | ||||||
|                 U.id = NewDefaultUseridStockUUID; |  | ||||||
|                 U.userRole = SecurityObjects::ROOT; |  | ||||||
|                 U.creationDate = std::time(nullptr); |  | ||||||
|                 U.validated = true; |  | ||||||
|                 U.name = "Default User"; |  | ||||||
|                 U.description = "Default user should be deleted."; |  | ||||||
|                 U.changePassword = true; |  | ||||||
|                 StorageService()->UserDB().CreateUser("SYSTEM", U, true); |  | ||||||
|                 AppServiceRegistry().Set("defaultusercreated", true); |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -7,46 +7,15 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "SpecialUserHelpers.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     int StorageService::Start() { |     int Storage::Start() { | ||||||
| 		std::lock_guard		Guard(Mutex_); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
| 		StorageClass::Start(); | 		StorageClass::Start(); | ||||||
|  | 		Create_Tables(); | ||||||
|         UserCache_ = std::make_unique<OpenWifi::UserCache>(64,1200000,true); | 		InitializeDefaultUser(); | ||||||
|         SubCache_ = std::make_unique<OpenWifi::UserCache>(2048,1200000,false); |  | ||||||
|         UserTokenCache_ = std::make_unique<OpenWifi::TokenCache>(64,1200000, true); |  | ||||||
|         SubTokenCache_ = std::make_unique<OpenWifi::TokenCache>(2048,1200000,false); |  | ||||||
|  |  | ||||||
|         UserDB_ = std::make_unique<OpenWifi::BaseUserDB>("Users", "usr", dbType_,*Pool_, Logger(), UserCache_.get(), true); |  | ||||||
|         SubDB_ = std::make_unique<OpenWifi::BaseUserDB>("Subscribers", "sub", dbType_,*Pool_, Logger(), SubCache_.get(), false); |  | ||||||
|         UserTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("Tokens", "tok", dbType_,*Pool_, Logger(), UserTokenCache_.get(), true); |  | ||||||
|         SubTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("SubTokens", "stk", dbType_,*Pool_, Logger(), SubTokenCache_.get(), false); |  | ||||||
|  |  | ||||||
|         PreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("Preferences", "pre", dbType_,*Pool_, Logger()); |  | ||||||
|         SubPreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("SubPreferences", "prs", dbType_,*Pool_, Logger()); |  | ||||||
|         ActionLinksDB_ = std::make_unique<OpenWifi::ActionLinkDB>("Actions", "act", dbType_,*Pool_, Logger()); |  | ||||||
|         AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("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()); |  | ||||||
|  |  | ||||||
|         UserDB_->Create(); |  | ||||||
|         SubDB_->Create(); |  | ||||||
|         UserTokenDB_->Create(); |  | ||||||
|         SubTokenDB_->Create(); |  | ||||||
|         ActionLinksDB_->Create(); |  | ||||||
|         PreferencesDB_->Create(); |  | ||||||
|         SubPreferencesDB_->Create(); |  | ||||||
|         AvatarDB_->Create(); |  | ||||||
|         SubAvatarDB_->Create(); |  | ||||||
|         LoginDB_->Create(); |  | ||||||
|         SubLoginDB_->Create(); |  | ||||||
|  |  | ||||||
| 		OpenWifi::SpecialUserHelpers::InitializeDefaultUser(); |  | ||||||
|  |  | ||||||
| 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | ||||||
| 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | ||||||
| @@ -56,8 +25,8 @@ namespace OpenWifi { | |||||||
| 		return 0; | 		return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void StorageService::Stop() { |     void Storage::Stop() { | ||||||
|         Logger().notice("Stopping."); |         Logger_.notice("Stopping."); | ||||||
|         Timer_.stop(); |         Timer_.stop(); | ||||||
|         StorageClass::Stop(); |         StorageClass::Stop(); | ||||||
|     } |     } | ||||||
| @@ -65,10 +34,9 @@ namespace OpenWifi { | |||||||
|     void Archiver::onTimer(Poco::Timer &timer) { |     void Archiver::onTimer(Poco::Timer &timer) { | ||||||
|         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); |         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); | ||||||
|         logger.information("Squiggy the DB: removing old tokens."); |         logger.information("Squiggy the DB: removing old tokens."); | ||||||
|         StorageService()->SubTokenDB().CleanExpiredTokens(); |         StorageService()->CleanExpiredTokens(); | ||||||
|         StorageService()->UserTokenDB().CleanExpiredTokens(); |  | ||||||
|         logger.information("Squiggy the DB: removing old actionLinks."); |         logger.information("Squiggy the DB: removing old actionLinks."); | ||||||
|         StorageService()->ActionLinksDB().CleanOldActionLinks(); |         StorageService()->CleanOldActionLinks(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,69 +15,138 @@ | |||||||
|  |  | ||||||
| #include "Poco/Timer.h" | #include "Poco/Timer.h" | ||||||
|  |  | ||||||
| #include "storage/orm_users.h" |  | ||||||
| #include "storage/orm_tokens.h" |  | ||||||
| #include "storage/orm_preferences.h" |  | ||||||
| #include "storage/orm_actionLinks.h" |  | ||||||
| #include "storage/orm_avatar.h" |  | ||||||
| #include "storage/orm_logins.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static const std::string AllEmailTemplatesFieldsForCreation { | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllEmailTemplatesFieldsForSelect { | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllEmailTemplatesFieldsForUpdate { | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     class Archiver { |     class Archiver { | ||||||
|     public: |     public: | ||||||
|         void onTimer(Poco::Timer & timer); |         void onTimer(Poco::Timer & timer); | ||||||
|     private: |     private: | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class StorageService : public StorageClass { |     class Storage : public StorageClass { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|         static auto instance() { |         enum AUTH_ERROR { | ||||||
|             static auto instance_ = new StorageService; |             SUCCESS, | ||||||
|  |             PASSWORD_CHANGE_REQUIRED, | ||||||
|  |             PASSWORD_DOES_NOT_MATCH, | ||||||
|  |             PASSWORD_ALREADY_USED, | ||||||
|  |             USERNAME_PENDING_VERIFICATION, | ||||||
|  |             PASSWORD_INVALID, | ||||||
|  |             INTERNAL_ERROR | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         enum USER_TYPE { | ||||||
|  |             UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, SPECIAL | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         typedef std::string USER_ID_TYPE; | ||||||
|  |  | ||||||
|  |         static USER_TYPE to_userType(const std::string &U) { | ||||||
|  |             if (U=="root") | ||||||
|  |                 return ROOT; | ||||||
|  |             else if (U=="admin") | ||||||
|  |                 return ADMIN; | ||||||
|  |             else if (U=="subscriber") | ||||||
|  |                 return SUBSCRIBER; | ||||||
|  |             else if (U=="csr") | ||||||
|  |                 return CSR; | ||||||
|  |             else if (U=="system") | ||||||
|  |                 return SYSTEM; | ||||||
|  |             else if (U=="SPECIAL") | ||||||
|  |                 return SPECIAL; | ||||||
|  |             return UNKNOWN; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static std::string from_userType(USER_TYPE U) { | ||||||
|  |             switch(U) { | ||||||
|  |                 case ROOT: return "root"; | ||||||
|  |                 case ADMIN: return "admin"; | ||||||
|  |                 case SUBSCRIBER: return "subscriber"; | ||||||
|  |                 case CSR: return "csr"; | ||||||
|  |                 case SYSTEM: return "system"; | ||||||
|  |                 case SPECIAL: return "special"; | ||||||
|  |                 case UNKNOWN: | ||||||
|  |                 default: return "unknown"; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static Storage *instance() { | ||||||
|  |             static auto * instance_ = new Storage; | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int 	Start() override; |         int 	Start() override; | ||||||
|         void 	Stop() override; |         void 	Stop() override; | ||||||
|  |  | ||||||
|         OpenWifi::BaseUserDB & UserDB() { return *UserDB_; } |         /* | ||||||
|         OpenWifi::BaseUserDB & SubDB() { return *SubDB_; } |          *  All user management functions | ||||||
|         OpenWifi::BaseTokenDB & UserTokenDB() { return *UserTokenDB_; } |          */ | ||||||
|         OpenWifi::BaseTokenDB & SubTokenDB() { return *SubTokenDB_; } |         bool InitializeDefaultUser(); | ||||||
|         OpenWifi::PreferencesDB & PreferencesDB() { return *PreferencesDB_; } |         bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false); | ||||||
|         OpenWifi::PreferencesDB & SubPreferencesDB() { return *SubPreferencesDB_; } |         bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); | ||||||
|         OpenWifi::ActionLinkDB & ActionLinksDB() { return *ActionLinksDB_; } |         bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); | ||||||
|         OpenWifi::AvatarDB & AvatarDB() { return *AvatarDB_; } |         bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); | ||||||
|         OpenWifi::AvatarDB & SubAvatarDB() { return *SubAvatarDB_; } |         bool SetOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner); | ||||||
|         OpenWifi::LoginDB & LoginDB() { return *LoginDB_; } |         bool SetLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location); | ||||||
|         OpenWifi::LoginDB & SubLoginDB() { return *SubLoginDB_; } |         AUTH_ERROR ChangePassword(const std::string & Admin, USER_ID_TYPE & Id, const std::string &OldPassword, const std::string &NewPassword); | ||||||
|  |         bool AddNotes(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Notes); | ||||||
|  |         bool SetPolicyChange(const std::string & Admin, USER_ID_TYPE & Id, const std::string &NewPolicy); | ||||||
|  |         bool UpdateUserInfo(const std::string & Admin, USER_ID_TYPE & Id, SecurityObjects::UserInfo &UInfo); | ||||||
|  |         bool GetUsers( uint64_t Offset, uint64_t Limit, SecurityObjects::UserInfoVec & Users); | ||||||
|  |         bool SetLastLogin(USER_ID_TYPE & Id); | ||||||
|  |  | ||||||
|  |         bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); | ||||||
|  |         bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); | ||||||
|  |         bool DeleteAvatar(const std::string & Admin, std::string &Id); | ||||||
|  |  | ||||||
|  |         bool AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut); | ||||||
|  |         bool RevokeToken( std::string & Token ); | ||||||
|  |         bool IsTokenRevoked( std::string & Token ); | ||||||
|  |         bool CleanExpiredTokens(); | ||||||
|  |         bool RevokeAllTokens( std::string & UserName ); | ||||||
|  |         bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          *  All ActionLinks functions | ||||||
|  |          */ | ||||||
|  |         bool CreateAction( SecurityObjects::ActionLink & A); | ||||||
|  |         bool DeleteAction(std::string &ActionId); | ||||||
|  |         bool CompleteAction(std::string &ActionId); | ||||||
|  |         bool CancelAction(std::string &ActionId); | ||||||
|  |         bool SentAction(std::string &ActionId); | ||||||
|  |         bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); | ||||||
|  |         bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); | ||||||
|  |         void CleanOldActionLinks(); | ||||||
|  |  | ||||||
| 	  private: | 	  private: | ||||||
|  |         int Create_Tables(); | ||||||
|         std::unique_ptr<OpenWifi::BaseUserDB>           UserDB_; |         int Create_UserTable(); | ||||||
|         std::unique_ptr<OpenWifi::BaseUserDB>           SubDB_; |         int Create_AvatarTable(); | ||||||
|         std::unique_ptr<OpenWifi::BaseTokenDB>          UserTokenDB_; |         int Create_TokensTable(); | ||||||
|         std::unique_ptr<OpenWifi::BaseTokenDB>          SubTokenDB_; |         int Create_ActionLinkTable(); | ||||||
|         std::unique_ptr<OpenWifi::PreferencesDB>        PreferencesDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::PreferencesDB>        SubPreferencesDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::ActionLinkDB>         ActionLinksDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::AvatarDB>             AvatarDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::AvatarDB>             SubAvatarDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::LoginDB>              LoginDB_; |  | ||||||
|         std::unique_ptr<OpenWifi::LoginDB>              SubLoginDB_; |  | ||||||
|  |  | ||||||
|         std::unique_ptr<OpenWifi::UserCache>            UserCache_; |  | ||||||
|         std::unique_ptr<OpenWifi::UserCache>            SubCache_; |  | ||||||
|         std::unique_ptr<OpenWifi::TokenCache>           UserTokenCache_; |  | ||||||
|         std::unique_ptr<OpenWifi::TokenCache>           SubTokenCache_; |  | ||||||
|  |  | ||||||
|         Poco::Timer                     Timer_; |         Poco::Timer                     Timer_; | ||||||
|         Archiver                        Archiver_; |         Archiver                        Archiver_; | ||||||
|         std::unique_ptr<Poco::TimerCallback<Archiver>>   Archivercallback_; |         std::unique_ptr<Poco::TimerCallback<Archiver>>   Archivercallback_; | ||||||
|  |  | ||||||
|  |         /// This is to support a mistake that was deployed... | ||||||
|  |         void ReplaceOldDefaultUUID(); | ||||||
|    }; |    }; | ||||||
|  |  | ||||||
|     inline auto StorageService() { return StorageService::instance(); }; |     inline Storage * StorageService() { return Storage::instance(); }; | ||||||
|  |  | ||||||
| }  // namespace | }  // namespace | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										173
									
								
								src/TotpCache.h
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								src/TotpCache.h
									
									
									
									
									
								
							| @@ -1,173 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2022-01-31. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #ifndef OWSEC_TOTPCACHE_H |  | ||||||
| #define OWSEC_TOTPCACHE_H |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "seclibs/cpptotp/bytes.h" |  | ||||||
| #include "seclibs/qrcode/qrcodegen.hpp" |  | ||||||
| #include "seclibs/cpptotp/otp.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     class TotpCache : public SubSystemServer { |  | ||||||
|     public: |  | ||||||
|  |  | ||||||
|         struct Entry { |  | ||||||
|             bool        Subscriber=false; |  | ||||||
|             uint64_t    Start = 0; |  | ||||||
|             uint64_t    Done = 0 ; |  | ||||||
|             uint64_t    Verifications = 0 ; |  | ||||||
|             std::string Secret; |  | ||||||
|             std::string QRCode; |  | ||||||
|             std::string LastCode; |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         static auto instance() { |  | ||||||
|             static auto instance = new TotpCache; |  | ||||||
|             return instance; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         static std::string GenerateSecret(uint Size, std::string & Base32Secret) { |  | ||||||
|             std::string R; |  | ||||||
|  |  | ||||||
|             for(;Size;Size--) { |  | ||||||
|                 R += (char) MicroService::instance().Random(33,127); |  | ||||||
|             } |  | ||||||
|             Base32Secret = CppTotp::Bytes::toBase32( CppTotp::Bytes::ByteString{ (const u_char *)R.c_str()}); |  | ||||||
|             return R; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { |  | ||||||
|  |  | ||||||
|             std::string uri{ |  | ||||||
|                 "otpauth://totp/" + Issuer_ + ":" + |  | ||||||
|                 email + "?secret=" + Secret + "&issuer=" + Issuer_ |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             qrcodegen::QrCode qr0 = qrcodegen::QrCode::encodeText(uri.c_str(), qrcodegen::QrCode::Ecc::MEDIUM); |  | ||||||
|             std::string svg = qrcodegen::toSvgString(qr0, 4);  // See QrCodeGeneratorDemo |  | ||||||
|             return svg; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { |  | ||||||
|             uint64_t Now = std::time(nullptr); |  | ||||||
|             uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6); |  | ||||||
|             char buffer[16]; |  | ||||||
|             sprintf(buffer,"%06u",p); |  | ||||||
|             Expecting = buffer; |  | ||||||
|             return Code == buffer; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int Start() override { |  | ||||||
|             Issuer_ = MicroService::instance().ConfigGetString("totp.issuer","OpenWiFi"); |  | ||||||
|             return 0; |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         void Stop() override { |  | ||||||
|  |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         inline bool StartValidation(const SecurityObjects::UserInfo &User, bool Subscriber, std::string & QRCode, bool Reset) { |  | ||||||
|             auto Hint = Cache_.find(User.id); |  | ||||||
|             if(Hint!=Cache_.end() && Hint->second.Subscriber==Subscriber) { |  | ||||||
|                 if(Reset) { |  | ||||||
|                     std::string Base32Secret; |  | ||||||
|                     Hint->second.Subscriber = Subscriber; |  | ||||||
|                     Hint->second.Start = std::time(nullptr); |  | ||||||
|                     Hint->second.Done = 0; |  | ||||||
|                     Hint->second.Verifications = 0; |  | ||||||
|                     Hint->second.Secret = GenerateSecret(20,Base32Secret); |  | ||||||
|                     Hint->second.QRCode = QRCode = GenerateQRCode(Base32Secret, User.email); |  | ||||||
|                     Hint->second.LastCode.clear(); |  | ||||||
|                 } else { |  | ||||||
|                     QRCode = Hint->second.QRCode; |  | ||||||
|                 } |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             std::string Base32Secret; |  | ||||||
|             auto Secret = GenerateSecret(20, Base32Secret); |  | ||||||
|             QRCode = GenerateQRCode(Base32Secret, User.email); |  | ||||||
|  |  | ||||||
|             Entry E{ .Subscriber = Subscriber, |  | ||||||
|                      .Start = (uint64_t )std::time(nullptr), |  | ||||||
|                      .Done = 0, |  | ||||||
|                      .Verifications = 0, |  | ||||||
|                      .Secret = Secret, |  | ||||||
|                      .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, uint64_t & ErrorCode, std::string & ErrorText ) { |  | ||||||
|             auto Hint = Cache_.find(User.id); |  | ||||||
|             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)) { |  | ||||||
|                     NextIndex++; |  | ||||||
|                     Hint->second.Verifications++; |  | ||||||
|                     MoreCodes = true; |  | ||||||
|                     Hint->second.LastCode = Code; |  | ||||||
|                     return true; |  | ||||||
|                 } else if (NextIndex == 2 && Hint->second.Verifications == 1 && Code != Hint->second.LastCode && |  | ||||||
|                             ValidateCode(Hint->second.Secret, Code, Expecting) ) { |  | ||||||
|                     MoreCodes = false; |  | ||||||
|                     Hint->second.Done = Now; |  | ||||||
|                     return true; |  | ||||||
|                 } else { |  | ||||||
|                     if(!ValidateCode(Hint->second.Secret, Code, Expecting)) { |  | ||||||
|                         ErrorCode = 1; |  | ||||||
|                         ErrorText = "Invalid code."; |  | ||||||
|                         return false; |  | ||||||
|                     } else if(NextIndex!=1 && NextIndex != 2) { |  | ||||||
|                         ErrorCode = 2; |  | ||||||
|                         ErrorText = "Invalid Index"; |  | ||||||
|                         return false; |  | ||||||
|                     } else if(Code == Hint->second.LastCode) { |  | ||||||
|                         ErrorCode = 3; |  | ||||||
|                         ErrorText = "Code is repeated. Must be new code."; |  | ||||||
|                         return false; |  | ||||||
|                     } |  | ||||||
|                     ErrorCode = 5; |  | ||||||
|                     ErrorText = "Invalid protocol sequence."; |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 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 = 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); |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|         std::map<std::string,Entry>     Cache_; |  | ||||||
|         std::string                     Issuer_; |  | ||||||
|  |  | ||||||
|         TotpCache() noexcept: |  | ||||||
|             SubSystemServer("TOTP-system", "TOTP-SVR", "totp") { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     inline auto TotpCache() { return TotpCache::instance(); } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif //OWSEC_TOTPCACHE_H |  | ||||||
| @@ -1,93 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-11-30. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "Poco/JSON/Parser.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     inline void API_Proxy( Poco::Logger &Logger, |  | ||||||
|                     Poco::Net::HTTPServerRequest *Request, |  | ||||||
|                     Poco::Net::HTTPServerResponse *Response, |  | ||||||
|                     const char * ServiceType, |  | ||||||
|                     const char * PathRewrite, |  | ||||||
|                     uint64_t msTimeout_ = 10000 ) { |  | ||||||
|         try { |  | ||||||
|             auto Services = MicroService::instance().GetServices(ServiceType); |  | ||||||
|             for(auto const &Svc:Services) { |  | ||||||
|                 Poco::URI   SourceURI(Request->getURI()); |  | ||||||
|                 Poco::URI	DestinationURI(Svc.PrivateEndPoint); |  | ||||||
|                 DestinationURI.setPath(PathRewrite); |  | ||||||
|                 DestinationURI.setQuery(SourceURI.getQuery()); |  | ||||||
|  |  | ||||||
|                 // std::cout << "     Source: " << SourceURI.toString() << std::endl; |  | ||||||
|                 // std::cout << "Destination: " << DestinationURI.toString() << std::endl; |  | ||||||
|  |  | ||||||
|                 Poco::Net::HTTPSClientSession Session(DestinationURI.getHost(), DestinationURI.getPort()); |  | ||||||
|                 Session.setKeepAlive(true); |  | ||||||
|                 Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); |  | ||||||
|                 Poco::Net::HTTPRequest ProxyRequest(Request->getMethod(), |  | ||||||
|                                                     DestinationURI.getPathAndQuery(), |  | ||||||
|                                                     Poco::Net::HTTPMessage::HTTP_1_1); |  | ||||||
|                 if(Request->has("Authorization")) { |  | ||||||
|                     ProxyRequest.add("Authorization", Request->get("Authorization")); |  | ||||||
|                 } else { |  | ||||||
|                     ProxyRequest.add("X-API-KEY", Svc.AccessKey); |  | ||||||
|                     ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) { |  | ||||||
|                     Session.sendRequest(ProxyRequest); |  | ||||||
|                     Poco::Net::HTTPResponse ProxyResponse; |  | ||||||
|                     Session.receiveResponse(ProxyResponse); |  | ||||||
|                     Response->setStatus(ProxyResponse.getStatus()); |  | ||||||
|                     Response->send(); |  | ||||||
|                     return; |  | ||||||
|                 } else { |  | ||||||
|                     Poco::JSON::Parser P; |  | ||||||
|                     std::stringstream SS; |  | ||||||
|                     try { |  | ||||||
|                         auto Body = P.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                         Poco::JSON::Stringifier::condense(Body,SS); |  | ||||||
|                         SS << "\r\n\r\n"; |  | ||||||
|                     } catch(const Poco::Exception &E) { |  | ||||||
|                         Logger.log(E); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     if(SS.str().empty()) { |  | ||||||
|                         Session.sendRequest(ProxyRequest); |  | ||||||
|                     } else { |  | ||||||
|                         ProxyRequest.setContentType("application/json"); |  | ||||||
|                         ProxyRequest.setContentLength(SS.str().size()); |  | ||||||
|                         std::ostream & os = Session.sendRequest(ProxyRequest); |  | ||||||
|                         os << SS.str() ; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     Poco::Net::HTTPResponse ProxyResponse; |  | ||||||
|                     std::stringstream SSR; |  | ||||||
|                     try { |  | ||||||
|                         std::istream &ProxyResponseStream = Session.receiveResponse(ProxyResponse); |  | ||||||
|                         Poco::JSON::Parser  P2; |  | ||||||
|                         auto ProxyResponseBody = P2.parse(ProxyResponseStream).extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                         Poco::JSON::Stringifier::condense(ProxyResponseBody,SSR); |  | ||||||
|                         Response->setContentType("application/json"); |  | ||||||
|                         Response->setContentLength(SSR.str().size()); |  | ||||||
|                         Response->setStatus(ProxyResponse.getStatus()); |  | ||||||
|                         Response->sendBuffer(SSR.str().c_str(),SSR.str().size()); |  | ||||||
|                         return; |  | ||||||
|                     } catch( const Poco::Exception & E) { |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                     Response->setStatus(ProxyResponse.getStatus()); |  | ||||||
|                     Response->send(); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } catch (const Poco::Exception &E) { |  | ||||||
|             Logger.log(E); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -2327,7 +2327,7 @@ namespace OpenWifi { | |||||||
|             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { |             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { | ||||||
|                 auto schema = json::parse(GitSchema); |                 auto schema = json::parse(GitSchema); | ||||||
|                 Validator_->set_root_schema(schema); |                 Validator_->set_root_schema(schema); | ||||||
|                 Logger().information("Using uCentral validation schema from GIT."); |                 Logger_.information("Using uCentral validation schema from GIT."); | ||||||
|             } else { |             } else { | ||||||
|                 std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" }; |                 std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" }; | ||||||
|                 std::ifstream       input(FileName); |                 std::ifstream       input(FileName); | ||||||
| @@ -2336,11 +2336,11 @@ namespace OpenWifi { | |||||||
|                 input.close(); |                 input.close(); | ||||||
|                 auto schema = json::parse(schema_file.str()); |                 auto schema = json::parse(schema_file.str()); | ||||||
|                 Validator_->set_root_schema(schema); |                 Validator_->set_root_schema(schema); | ||||||
|                 Logger().information("Using uCentral validation schema from local file."); |                 Logger_.information("Using uCentral validation schema from local file."); | ||||||
|             } |             } | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|             Validator_->set_root_schema(DefaultUCentralSchema); |             Validator_->set_root_schema(DefaultUCentralSchema); | ||||||
|             Logger().information("Using uCentral validation from built-in default."); |             Logger_.information("Using uCentral validation from built-in default."); | ||||||
|         } |         } | ||||||
|         Initialized_ = Working_ = true; |         Initialized_ = Working_ = true; | ||||||
|     } |     } | ||||||
| @@ -2471,7 +2471,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ConfigurationValidator::reinitialize(Poco::Util::Application &self) { |     void ConfigurationValidator::reinitialize(Poco::Util::Application &self) { | ||||||
|         Logger().information("Reinitializing."); |         Logger_.information("Reinitializing."); | ||||||
|         Working_ = Initialized_ = false; |         Working_ = Initialized_ = false; | ||||||
|         Init(); |         Init(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,7 +2,8 @@ | |||||||
| // Created by stephane bourque on 2021-09-14. | // Created by stephane bourque on 2021-09-14. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef OWPROV_CONFIGURATIONVALIDATOR_H | ||||||
|  | #define OWPROV_CONFIGURATIONVALIDATOR_H | ||||||
|  |  | ||||||
| #include <nlohmann/json-schema.hpp> | #include <nlohmann/json-schema.hpp> | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| @@ -42,3 +43,4 @@ namespace OpenWifi { | |||||||
|     inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } |     inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //OWPROV_CONFIGURATIONVALIDATOR_H | ||||||
|   | |||||||
| @@ -2,7 +2,8 @@ | |||||||
| // Created by stephane bourque on 2021-10-08. | // Created by stephane bourque on 2021-10-08. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef OWPROV_COUNTRYCODES_H | ||||||
|  | #define OWPROV_COUNTRYCODES_H | ||||||
|  |  | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <string> | #include <string> | ||||||
| @@ -269,3 +270,4 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //OWPROV_COUNTRYCODES_H | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| //	Created by Stephane Bourque on 2021-03-04. | //	Created by Stephane Bourque on 2021-03-04. | ||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  | #ifndef UCENTRALGW_KAFKA_TOPICS_H | ||||||
| #pragma once | #define UCENTRALGW_KAFKA_TOPICS_H | ||||||
|  |  | ||||||
| namespace OpenWifi::KafkaTopics { | namespace OpenWifi::KafkaTopics { | ||||||
| 	static const std::string HEALTHCHECK{"healthcheck"}; | 	static const std::string HEALTHCHECK{"healthcheck"}; | ||||||
| @@ -17,7 +17,6 @@ namespace OpenWifi::KafkaTopics { | |||||||
| 	static const std::string COMMAND{"command"}; | 	static const std::string COMMAND{"command"}; | ||||||
| 	static const std::string SERVICE_EVENTS{"service_events"}; | 	static const std::string SERVICE_EVENTS{"service_events"}; | ||||||
| 	static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; | 	static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; | ||||||
| 	static const std::string DEVICE_TELEMETRY{"device_telemetry"}; |  | ||||||
|  |  | ||||||
| 	namespace ServiceEvents { | 	namespace ServiceEvents { | ||||||
| 		static const std::string EVENT_JOIN{"join"}; | 		static const std::string EVENT_JOIN{"join"}; | ||||||
| @@ -38,3 +37,4 @@ namespace OpenWifi::KafkaTopics { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif // UCENTRALGW_KAFKA_TOPICS_H | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,38 +1,42 @@ | |||||||
| // | // | ||||||
| // Created by stephane bourque on 2021-11-16. | //	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 | #ifndef UCENTRALGW_UCENTRALTYPES_H | ||||||
|  | #define UCENTRALGW_UCENTRALTYPES_H | ||||||
|  |  | ||||||
| #include <map> |  | ||||||
| #include <utility> |  | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <functional> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <queue> | #include <map> | ||||||
|  | #include <functional> | ||||||
| #include <list> | #include <list> | ||||||
| #include <set> | #include <utility> | ||||||
|  | #include <queue> | ||||||
|  |  | ||||||
|  | #include "Poco/StringTokenizer.h" | ||||||
|  | #include "Poco/JSON/Parser.h" | ||||||
|  | #include "Poco/JSON/Stringifier.h" | ||||||
|  |  | ||||||
| namespace OpenWifi::Types { | namespace OpenWifi::Types { | ||||||
|     typedef std::pair<std::string,std::string>                  StringPair; |     typedef std::pair<std::string,std::string>              StringPair; | ||||||
|     typedef std::vector<StringPair>	                            StringPairVec; | 	typedef std::vector<StringPair>	                        StringPairVec; | ||||||
|     typedef std::queue<StringPair>	                            StringPairQueue; |     typedef std::queue<StringPair>	                        StringPairQueue; | ||||||
|     typedef std::vector<std::string>						    StringVec; | 	typedef std::vector<std::string>						StringVec; | ||||||
|     typedef std::set<std::string>                               StringSet; | 	typedef std::set<std::string>                           StringSet; | ||||||
|     typedef std::map<std::string,std::set<std::string>>		    StringMapStringSet; | 	typedef std::map<std::string,std::set<std::string>>		StringMapStringSet; | ||||||
|     typedef std::function<void(const std::string &, const std::string &)>       TopicNotifyFunction; | 	typedef std::function<void(std::string, std::string)>   TopicNotifyFunction; | ||||||
|     typedef std::list<std::pair<TopicNotifyFunction,int>>       TopicNotifyFunctionList; | 	typedef std::list<std::pair<TopicNotifyFunction,int>>   TopicNotifyFunctionList; | ||||||
|     typedef std::map<std::string, TopicNotifyFunctionList>      NotifyTable; | 	typedef std::map<std::string, TopicNotifyFunctionList>  NotifyTable; | ||||||
|     typedef std::map<std::string,uint64_t>                      CountedMap; |     typedef std::map<std::string,uint64_t>                  CountedMap; | ||||||
|     typedef std::vector<uint64_t>                               TagList; |     typedef std::vector<uint64_t>                           TagList; | ||||||
|     typedef std::string                                         UUID_t; |     typedef std::string                                     UUID_t; | ||||||
|     typedef std::vector<UUID_t>                                 UUIDvec_t; |     typedef std::vector<UUID_t>                             UUIDvec_t; | ||||||
|     typedef std::map<std::string,std::map<uint32_t,uint64_t>>   Counted3DMapSII; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |     inline void UpdateCountedMap(CountedMap &M, const std::string &S, uint64_t Increment=1) { | ||||||
|  |  | ||||||
|     inline void UpdateCountedMap(OpenWifi::Types::CountedMap &M, const std::string &S, uint64_t Increment=1) { |  | ||||||
|         auto it = M.find(S); |         auto it = M.find(S); | ||||||
|         if(it==M.end()) |         if(it==M.end()) | ||||||
|             M[S] = Increment; |             M[S] = Increment; | ||||||
| @@ -40,21 +44,60 @@ namespace OpenWifi { | |||||||
|             it->second += Increment; |             it->second += Increment; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void UpdateCountedMap(OpenWifi::Types::Counted3DMapSII &M, const std::string &S, uint32_t Index, uint64_t Increment=1) { |     inline std::string to_string( const StringVec &V) { | ||||||
|         auto it = M.find(S); |         Poco::JSON::Array   O; | ||||||
|         if(it==M.end()) { |         for(const auto &i:V) { | ||||||
|             std::map<uint32_t,uint64_t> E; |             O.add(i); | ||||||
|             E[Index] = Increment; |  | ||||||
|             M[S] = E; |  | ||||||
|         } |         } | ||||||
|         else { |         std::stringstream SS; | ||||||
|             std::map<uint32_t,uint64_t> & IndexMap = it->second; |         Poco::JSON::Stringifier::stringify(O,SS); | ||||||
|             auto it_index = IndexMap.find(Index); |         return SS.str(); | ||||||
|             if(it_index == IndexMap.end()) { |     } | ||||||
|                 IndexMap[Index] = Increment; |  | ||||||
|             } else { |     inline std::string to_string( const StringPairVec &V) { | ||||||
|                 it_index->second += Increment; |         Poco::JSON::Array   O; | ||||||
|  |         for(const auto &i:V) { | ||||||
|  |             Poco::JSON::Array OO; | ||||||
|  |             OO.add(i.first); | ||||||
|  |             OO.add(i.second); | ||||||
|  |             O.add(OO); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         std::stringstream SS; | ||||||
|  |         Poco::JSON::Stringifier::stringify(O,SS); | ||||||
|  |         return SS.str(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void from_string(const std::string &S, StringPairVec &V) { | ||||||
|  |         try { | ||||||
|  |             Poco::JSON::Parser      P; | ||||||
|  |             auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>(); | ||||||
|  |  | ||||||
|  |             for(const auto &i:*O) { | ||||||
|  |                 auto Inner = i.extract<Poco::JSON::Array::Ptr>(); | ||||||
|  |                 for(const auto &j:*Inner) { | ||||||
|  |                     auto S1 = i[0].toString(); | ||||||
|  |                     auto S2 = i[1].toString(); | ||||||
|  |                     V.push_back(std::make_pair(S1,S2)); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     inline void from_string(const std::string &S, StringVec &V) { | ||||||
|  |         try { | ||||||
|  |             Poco::JSON::Parser      P; | ||||||
|  |             auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>(); | ||||||
|  |  | ||||||
|  |             for(auto const &i:*O) { | ||||||
|  |                 V.push_back(i.toString()); | ||||||
|  |             } | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // UCENTRALGW_UCENTRALTYPES_H | ||||||
|   | |||||||
| @@ -2,7 +2,8 @@ | |||||||
| // Created by stephane bourque on 2021-09-12. | // Created by stephane bourque on 2021-09-12. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef OWPROV_RESTAPI_ERRORS_H | ||||||
|  | #define OWPROV_RESTAPI_ERRORS_H | ||||||
|  |  | ||||||
| namespace OpenWifi::RESTAPI::Errors { | namespace OpenWifi::RESTAPI::Errors { | ||||||
|     static const std::string MissingUUID{"Missing UUID."}; |     static const std::string MissingUUID{"Missing UUID."}; | ||||||
| @@ -14,7 +15,7 @@ namespace OpenWifi::RESTAPI::Errors { | |||||||
|     static const std::string CouldNotBeDeleted{"Element could not be deleted."}; |     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 NameMustBeSet{"The name property must be set."}; | ||||||
|     static const std::string ConfigBlockInvalid{"Configuration block type invalid."}; |     static const std::string ConfigBlockInvalid{"Configuration block type invalid."}; | ||||||
|     static const std::string UnknownId{"Unknown UUID."}; |     static const std::string UnknownId{"Unknown management policy."}; | ||||||
|     static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."}; |     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 RecordNotCreated{"Record could not be created."}; | ||||||
|     static const std::string RecordNotUpdated{"Record could not be updated."}; |     static const std::string RecordNotUpdated{"Record could not be updated."}; | ||||||
| @@ -59,10 +60,6 @@ namespace OpenWifi::RESTAPI::Errors { | |||||||
|     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; |     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; | ||||||
|     static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; |     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 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"}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //OWPROV_RESTAPI_ERRORS_H | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef UCENTRALGW_RESTAPI_PROTOCOL_H | ||||||
|  | #define UCENTRALGW_RESTAPI_PROTOCOL_H | ||||||
|  |  | ||||||
| namespace OpenWifi::RESTAPI::Protocol { | namespace OpenWifi::RESTAPI::Protocol { | ||||||
| 	static const char * CAPABILITIES = "capabilities"; | 	static const char * CAPABILITIES = "capabilities"; | ||||||
| @@ -84,13 +85,11 @@ namespace OpenWifi::RESTAPI::Protocol { | |||||||
| 	static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; | 	static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; | ||||||
| 	static const char * GETLOGLEVELNAMES = "getloglevelnames"; | 	static const char * GETLOGLEVELNAMES = "getloglevelnames"; | ||||||
| 	static const char * STATS = "stats"; | 	static const char * STATS = "stats"; | ||||||
| 	static const char * PING = "ping"; |  | ||||||
| 	static const char * PARAMETERS = "parameters"; | 	static const char * PARAMETERS = "parameters"; | ||||||
| 	static const char * VALUE = "value"; | 	static const char * VALUE = "value"; | ||||||
| 	static const char * LASTONLY = "lastOnly"; | 	static const char * LASTONLY = "lastOnly"; | ||||||
| 	static const char * NEWEST = "newest"; | 	static const char * NEWEST = "newest"; | ||||||
| 	static const char * ACTIVESCAN = "activeScan"; | 	static const char * ACTIVESCAN = "activeScan"; | ||||||
| 	static const char * OVERRIDEDFS = "override_dfs"; |  | ||||||
| 	static const char * LIST = "list"; | 	static const char * LIST = "list"; | ||||||
| 	static const char * TAG = "tag"; | 	static const char * TAG = "tag"; | ||||||
| 	static const char * TAGLIST = "tagList"; | 	static const char * TAGLIST = "tagList"; | ||||||
| @@ -137,3 +136,5 @@ namespace OpenWifi::RESTAPI::Protocol { | |||||||
|     static const char * UI = "UI"; |     static const char * UI = "UI"; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif // UCENTRALGW_RESTAPI_PROTOCOL_H | ||||||
|   | |||||||
| @@ -33,8 +33,8 @@ namespace OpenWifi { | |||||||
|         int Start() override { |         int Start() override { | ||||||
|             std::lock_guard		Guard(Mutex_); |             std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|             Logger().setLevel(Poco::Message::PRIO_INFORMATION); |             Logger_.setLevel(Poco::Message::PRIO_NOTICE); | ||||||
|             Logger().notice("Starting."); |             Logger_.notice("Starting."); | ||||||
|             std::string DBType = MicroService::instance().ConfigGetString("storage.type"); |             std::string DBType = MicroService::instance().ConfigGetString("storage.type"); | ||||||
|  |  | ||||||
|             if (DBType == "sqlite") { |             if (DBType == "sqlite") { | ||||||
| @@ -51,6 +51,37 @@ namespace OpenWifi { | |||||||
|             Pool_->shutdown(); |             Pool_->shutdown(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { | ||||||
|  |             if(dbType_==sqlite) { | ||||||
|  |                 return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " "; | ||||||
|  |             } else if(dbType_==pgsql) { | ||||||
|  |                 return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; | ||||||
|  |             } else if(dbType_==mysql) { | ||||||
|  |                 return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; | ||||||
|  |             } | ||||||
|  |             return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         inline std::string ConvertParams(const std::string & S) const { | ||||||
|  |             std::string R; | ||||||
|  |             R.reserve(S.size()*2+1); | ||||||
|  |             if(dbType_==pgsql) { | ||||||
|  |                 auto Idx=1; | ||||||
|  |                 for(auto const & i:S) | ||||||
|  |                 { | ||||||
|  |                     if(i=='?') { | ||||||
|  |                         R += '$'; | ||||||
|  |                         R.append(std::to_string(Idx++)); | ||||||
|  |                     } else { | ||||||
|  |                         R += i; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 R = S; | ||||||
|  |             } | ||||||
|  |             return R; | ||||||
|  |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         inline int Setup_SQLite(); |         inline int Setup_SQLite(); | ||||||
|         inline int Setup_MySQL(); |         inline int Setup_MySQL(); | ||||||
| @@ -70,7 +101,7 @@ namespace OpenWifi { | |||||||
| #else | #else | ||||||
|  |  | ||||||
|     inline int StorageClass::Setup_SQLite() { |     inline int StorageClass::Setup_SQLite() { | ||||||
|         Logger().notice("SQLite StorageClass enabled."); |         Logger_.notice("SQLite StorageClass enabled."); | ||||||
|         dbType_ = sqlite; |         dbType_ = sqlite; | ||||||
|         auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); |         auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); | ||||||
|         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); |         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); | ||||||
| @@ -81,7 +112,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline int StorageClass::Setup_MySQL() { |     inline int StorageClass::Setup_MySQL() { | ||||||
|         Logger().notice("MySQL StorageClass enabled."); |         Logger_.notice("MySQL StorageClass enabled."); | ||||||
|         dbType_ = mysql; |         dbType_ = mysql; | ||||||
|         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); |         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); | ||||||
|         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); |         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); | ||||||
| @@ -106,7 +137,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline int StorageClass::Setup_PostgreSQL() { |     inline int StorageClass::Setup_PostgreSQL() { | ||||||
|         Logger().notice("PostgreSQL StorageClass enabled."); |         Logger_.notice("PostgreSQL StorageClass enabled."); | ||||||
|         dbType_ = pgsql; |         dbType_ = pgsql; | ||||||
|         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); |         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); | ||||||
|         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); |         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
| #pragma once | #ifndef __OPENWIFI_ORM_H__ | ||||||
|  | #define __OPENWIFI_ORM_H__ | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <memory> | #include <memory> | ||||||
| @@ -32,8 +33,7 @@ namespace ORM { | |||||||
|         FT_BIGINT, |         FT_BIGINT, | ||||||
|         FT_TEXT, |         FT_TEXT, | ||||||
|         FT_VARCHAR, |         FT_VARCHAR, | ||||||
|         FT_BLOB, |         FT_BLOB | ||||||
|         FT_BOOLEAN |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     enum Indextype { |     enum Indextype { | ||||||
| @@ -97,22 +97,21 @@ namespace ORM { | |||||||
|             case FT_INT:    return "INT"; |             case FT_INT:    return "INT"; | ||||||
|             case FT_BIGINT: return "BIGINT"; |             case FT_BIGINT: return "BIGINT"; | ||||||
|             case FT_TEXT:   return "TEXT"; |             case FT_TEXT:   return "TEXT"; | ||||||
|             case FT_BOOLEAN:   return "BOOLEAN"; |  | ||||||
|             case FT_VARCHAR: |             case FT_VARCHAR: | ||||||
|                 if(Size) |                 if(Size) | ||||||
|                     return std::string("VARCHAR(") + std::to_string(Size) + std::string(")"); |                     return std::string("VARCHAR(") + std::to_string(Size) + std::string(")"); | ||||||
|                 else |                 else | ||||||
|                     return "TEXT"; |                     return "TEXT"; | ||||||
|             case FT_BLOB: |                 case FT_BLOB: | ||||||
|                 if(Type==OpenWifi::DBType::mysql) |                     if(Type==OpenWifi::DBType::mysql) | ||||||
|                     return "LONGBLOB"; |                         return "LONGBLOB"; | ||||||
|                 else if(Type==OpenWifi::DBType::pgsql) |                     else if(Type==OpenWifi::DBType::pgsql) | ||||||
|                     return "BYTEA"; |                         return "BYTEA"; | ||||||
|                 else if(Type==OpenWifi::DBType::sqlite) |                     else if(Type==OpenWifi::DBType::sqlite) | ||||||
|                     return "BLOB"; |                         return "BLOB"; | ||||||
|                 default: |                     default: | ||||||
|                     assert(false); |                         assert(false); | ||||||
|                     return ""; |                         return ""; | ||||||
|         } |         } | ||||||
|         assert(false); |         assert(false); | ||||||
|         return ""; |         return ""; | ||||||
| @@ -155,46 +154,28 @@ namespace ORM { | |||||||
|         return S; |         return S; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     template <typename RecordType> class DBCache { |  | ||||||
|     public: |  | ||||||
|         DBCache(unsigned Size, unsigned Timeout) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         virtual void Create(const RecordType &R)=0; |  | ||||||
|         virtual bool GetFromCache(const std::string &FieldName, const std::string &Value, RecordType &R)=0; |  | ||||||
|         virtual void UpdateCache(const RecordType &R)=0; |  | ||||||
|         virtual void Delete(const std::string &FieldName, const std::string &Value)=0; |  | ||||||
|     private: |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     template <typename RecordTuple, typename RecordType> class DB { |     template <typename RecordTuple, typename RecordType> class DB { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|         typedef const char * field_name_t; |  | ||||||
|  |  | ||||||
|         DB( OpenWifi::DBType dbtype, |         DB( OpenWifi::DBType dbtype, | ||||||
|             const char *TableName, |             const char *TableName, | ||||||
|             const FieldVec & Fields, |             const FieldVec & Fields, | ||||||
|             const IndexVec & Indexes, |             const IndexVec & Indexes, | ||||||
|             Poco::Data::SessionPool & Pool, |             Poco::Data::SessionPool & Pool, | ||||||
|             Poco::Logger &L, |                 Poco::Logger &L, | ||||||
|             const char *Prefix, |                 const char *Prefix): | ||||||
|             DBCache<RecordType> * Cache=nullptr): |                 Type(dbtype), | ||||||
|                 Type_(dbtype), |                 DBName(TableName), | ||||||
|                 TableName_(TableName), |  | ||||||
|                 Pool_(Pool), |                 Pool_(Pool), | ||||||
|                 Logger_(L), |                 Logger_(L), | ||||||
|                 Prefix_(Prefix), |                 Prefix_(Prefix) | ||||||
|                 Cache_(Cache) |  | ||||||
|         { |         { | ||||||
|             assert(RecordTuple::length == Fields.size()); |  | ||||||
|  |  | ||||||
|             bool first = true; |             bool first = true; | ||||||
|             int  Place=0; |             int  Place=0; | ||||||
|  |  | ||||||
|  |             assert( RecordTuple::length == Fields.size()); | ||||||
|  |  | ||||||
|             for(const auto &i:Fields) { |             for(const auto &i:Fields) { | ||||||
|  |  | ||||||
|                 FieldNames_[i.Name] = Place; |                 FieldNames_[i.Name] = Place; | ||||||
|                 if(!first) { |                 if(!first) { | ||||||
|                     CreateFields_ += ", "; |                     CreateFields_ += ", "; | ||||||
| @@ -205,7 +186,7 @@ namespace ORM { | |||||||
|                     SelectList_ += "("; |                     SelectList_ += "("; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 CreateFields_ += i.Name + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : ""); |                 CreateFields_ += i.Name + " " + FieldTypeToChar(Type, i.Type,i.Size) + (i.Index ? " unique primary key" : ""); | ||||||
|                 SelectFields_ += i.Name ; |                 SelectFields_ += i.Name ; | ||||||
|                 UpdateFields_ += i.Name + "=?"; |                 UpdateFields_ += i.Name + "=?"; | ||||||
|                 SelectList_ += "?"; |                 SelectList_ += "?"; | ||||||
| @@ -215,11 +196,11 @@ namespace ORM { | |||||||
|             SelectList_ += ")"; |             SelectList_ += ")"; | ||||||
|  |  | ||||||
|             if(!Indexes.empty()) { |             if(!Indexes.empty()) { | ||||||
|                 if(Type_==OpenWifi::DBType::sqlite || Type_==OpenWifi::DBType::pgsql) { |                 if(Type==OpenWifi::DBType::sqlite || Type==OpenWifi::DBType::pgsql) { | ||||||
|                     for(const auto &j:Indexes) { |                     for(const auto &j:Indexes) { | ||||||
|                         std::string IndexLine; |                         std::string IndexLine; | ||||||
|  |  | ||||||
|                         IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + TableName_+ " ("; |                         IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + DBName + " ("; | ||||||
|                         bool first_entry=true; |                         bool first_entry=true; | ||||||
|                         for(const auto &k:j.Entries) { |                         for(const auto &k:j.Entries) { | ||||||
|                             assert(FieldNames_.find(k.FieldName) != FieldNames_.end()); |                             assert(FieldNames_.find(k.FieldName) != FieldNames_.end()); | ||||||
| @@ -229,10 +210,10 @@ namespace ORM { | |||||||
|                             first_entry = false; |                             first_entry = false; | ||||||
|                             IndexLine += k.FieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ; |                             IndexLine += k.FieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ; | ||||||
|                         } |                         } | ||||||
|                         IndexLine += " )"; |                         IndexLine += " );"; | ||||||
|                         IndexCreation_.template emplace_back(IndexLine); |                         IndexCreation += IndexLine; | ||||||
|                     } |                     } | ||||||
|                 } else if(Type_==OpenWifi::DBType::mysql) { |                 } else if(Type==OpenWifi::DBType::mysql) { | ||||||
|                     bool firstIndex = true; |                     bool firstIndex = true; | ||||||
|                     std::string IndexLine; |                     std::string IndexLine; | ||||||
|                     for(const auto &j:Indexes) { |                     for(const auto &j:Indexes) { | ||||||
| @@ -251,7 +232,7 @@ namespace ORM { | |||||||
|                         } |                         } | ||||||
|                         IndexLine += " ) "; |                         IndexLine += " ) "; | ||||||
|                     } |                     } | ||||||
|                     IndexCreation_.template emplace_back(IndexLine); |                     IndexCreation = IndexLine; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -261,27 +242,22 @@ namespace ORM { | |||||||
|         [[nodiscard]] const std::string & SelectList() const { return SelectList_; }; |         [[nodiscard]] const std::string & SelectList() const { return SelectList_; }; | ||||||
|         [[nodiscard]] const std::string & UpdateFields() const { return UpdateFields_; }; |         [[nodiscard]] const std::string & UpdateFields() const { return UpdateFields_; }; | ||||||
|  |  | ||||||
|         inline std::string OP(field_name_t F, SqlComparison O , bool V) { |         inline std::string OP(const char *F, SqlComparison O , int V) { | ||||||
|             assert( FieldNames_.find(F) != FieldNames_.end() ); |  | ||||||
|             return std::string{"("} + F + SQLCOMPS[O] + (V ? "true" : "false") + ")" ; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         inline std::string OP(field_name_t F, SqlComparison O , int V) { |  | ||||||
|             assert( FieldNames_.find(F) != FieldNames_.end() ); |             assert( FieldNames_.find(F) != FieldNames_.end() ); | ||||||
|             return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; |             return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string OP(field_name_t F, SqlComparison O , uint64_t V) { |         inline std::string OP(const char *F, SqlComparison O , uint64_t V) { | ||||||
|             assert( FieldNames_.find(F) != FieldNames_.end() ); |             assert( FieldNames_.find(F) != FieldNames_.end() ); | ||||||
|             return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; |             return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::string OP(field_name_t F, SqlComparison O , const std::string & V) { |         std::string OP(const char *F, SqlComparison O , const std::string & V) { | ||||||
|             assert( FieldNames_.find(F) != FieldNames_.end() ); |             assert( FieldNames_.find(F) != FieldNames_.end() ); | ||||||
|             return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; |             return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::string OP(field_name_t F, SqlComparison O , const char * V) { |         std::string OP(const char *F, SqlComparison O , const char * V) { | ||||||
|             assert( FieldNames_.find(F) != FieldNames_.end() ); |             assert( FieldNames_.find(F) != FieldNames_.end() ); | ||||||
|             return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; |             return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; | ||||||
|         } |         } | ||||||
| @@ -302,61 +278,35 @@ namespace ORM { | |||||||
|             return std::string{"("} + P1 + BOPS[BOP] + OP(true, P2, More...); |             return std::string{"("} + P1 + BOPS[BOP] + OP(true, P2, More...); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool Upgrade() { |  | ||||||
|             uint32_t    To; |  | ||||||
|             return Upgrade(0, To); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         inline bool  Create() { |         inline bool  Create() { | ||||||
|             switch(Type_) { |             std::string S; | ||||||
|                 case OpenWifi::DBType::mysql: { |  | ||||||
|                     try { |  | ||||||
|                         Poco::Data::Session     Session = Pool_.get(); |  | ||||||
|                         std::string Statement = IndexCreation_.empty() ?    "create table if not exists " + TableName_ +" ( " + CreateFields_ + " )" : |  | ||||||
|                                                                             "create table if not exists " + TableName_ +" ( " + CreateFields_ + " ), " + IndexCreation_[0] + " )"; |  | ||||||
|                         Session << Statement , Poco::Data::Keywords::now; |  | ||||||
|                     } catch (const Poco::Exception &E) { |  | ||||||
|                         Logger_.error("Failure to create MySQL DB resources."); |  | ||||||
|                         Logger_.log(E); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|  |  | ||||||
|                 case OpenWifi::DBType::sqlite: { |             if(Type==OpenWifi::DBType::mysql) { | ||||||
|                     try { |                 if(IndexCreation.empty()) | ||||||
|                         Poco::Data::Session     Session = Pool_.get(); |                     S = "create table if not exists " + DBName +" ( " + CreateFields_ + " )" ; | ||||||
|                         std::string Statement = "create table if not exists " + TableName_ + " ( " + CreateFields_ + " )"; |                 else | ||||||
|                         Session << Statement , Poco::Data::Keywords::now; |                     S = "create table if not exists " + DBName +" ( " + CreateFields_ + " ), " + IndexCreation + " )"; | ||||||
|                         for(const auto &i:IndexCreation_) { |             } else if (Type==OpenWifi::DBType::pgsql || Type==OpenWifi::DBType::sqlite) { | ||||||
|                             Session << i , Poco::Data::Keywords::now; |                 S = "create table if not exists " + DBName + " ( " + CreateFields_ + " ); " + IndexCreation ; | ||||||
|                         } |  | ||||||
|                     } catch (const Poco::Exception &E) { |  | ||||||
|                         Logger_.error("Failure to create SQLITE DB resources."); |  | ||||||
|                         Logger_.log(E); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|  |  | ||||||
|                 case OpenWifi::DBType::pgsql: { |  | ||||||
|                     try { |  | ||||||
|                         Poco::Data::Session     Session = Pool_.get(); |  | ||||||
|                         std::string Statement = "create table if not exists " + TableName_ + " ( " + CreateFields_ + " )"; |  | ||||||
|                         Session << Statement , Poco::Data::Keywords::now; |  | ||||||
|                         for(const auto &i:IndexCreation_) { |  | ||||||
|                             Session << i , Poco::Data::Keywords::now; |  | ||||||
|                         } |  | ||||||
|                     } catch (const Poco::Exception &E) { |  | ||||||
|                         Logger_.error("Failure to create POSTGRESQL DB resources."); |  | ||||||
|                         Logger_.log(E); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|             } |             } | ||||||
|             return Upgrade(); |  | ||||||
|  |             // std::cout << "CREATE-DB: " << S << std::endl; | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|  |                 Poco::Data::Statement   CreateStatement(Session); | ||||||
|  |  | ||||||
|  |                 CreateStatement << S; | ||||||
|  |                 CreateStatement.execute(); | ||||||
|  |                 return true; | ||||||
|  |             } catch (const Poco::Exception &E) { | ||||||
|  |                 std::cout << "Exception while creating DB: " << E.name() << std::endl; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [[nodiscard]] std::string ConvertParams(const std::string & S) const { |         [[nodiscard]] std::string ConvertParams(const std::string & S) const { | ||||||
|             if(Type_!=OpenWifi::DBType::pgsql) |             if(Type!=OpenWifi::DBType::pgsql) | ||||||
|                 return S; |                 return S; | ||||||
|  |  | ||||||
|             std::string R; |             std::string R; | ||||||
| @@ -375,59 +325,45 @@ namespace ORM { | |||||||
|             return R; |             return R; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         void Convert( const RecordTuple &in , RecordType &out); |         void Convert( RecordTuple &in , RecordType &out); | ||||||
|         void Convert( const RecordType &in , RecordTuple &out); |         void Convert( RecordType &in , RecordTuple &out); | ||||||
|  |  | ||||||
|         inline const std::string & Prefix() { return Prefix_; }; |         inline const std::string & Prefix() { return Prefix_; }; | ||||||
|  |  | ||||||
|         bool CreateRecord( const RecordType & R) { |         bool CreateRecord( RecordType & R) { | ||||||
|             try { |             try { | ||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Insert(Session); |                 Poco::Data::Statement   Insert(Session); | ||||||
|  |  | ||||||
|                 RecordTuple RT; |                 RecordTuple RT; | ||||||
|                 Convert(R, RT); |                 Convert(R, RT); | ||||||
|                 std::string St = "insert into  " + TableName_ + " ( " + SelectFields_ + " ) values " + SelectList_; |                 std::string St = "insert into  " + DBName + " ( " + SelectFields_ + " ) values " + SelectList_; | ||||||
|                 Insert  << ConvertParams(St) , |                 Insert  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::use(RT); |                     Poco::Data::Keywords::use(RT); | ||||||
|                 Insert.execute(); |                 Insert.execute(); | ||||||
|  |  | ||||||
|                 if(Cache_) |  | ||||||
|                     Cache_->Create(R); |  | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             } catch (const Poco::Exception &E) { |             } catch (const Poco::Exception &E) { | ||||||
|                 Logger_.log(E); |                 Logger_.log(E); | ||||||
|             } |             } | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template<typename T> bool GetRecord(field_name_t FieldName, const T & Value,  RecordType & R) { |         template<typename T> bool GetRecord( const char * FieldName, T Value,  RecordType & R) { | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |  | ||||||
|  |  | ||||||
|                 if(Cache_) { |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|                     if(Cache_->GetFromCache(FieldName, Value, R)) |  | ||||||
|                         return true; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Select(Session); |                 Poco::Data::Statement   Select(Session); | ||||||
|                 RecordTuple             RT; |                 RecordTuple             RT; | ||||||
|  |  | ||||||
|                 std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" ; |                 std::string St = "select " + SelectFields_ + " from " + DBName + " where " + FieldName + "=?" ; | ||||||
|  |  | ||||||
|                 auto tValue{Value}; |  | ||||||
|  |  | ||||||
|                 Select  << ConvertParams(St) , |                 Select  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::into(RT), |                     Poco::Data::Keywords::into(RT), | ||||||
|                     Poco::Data::Keywords::use(tValue); |                     Poco::Data::Keywords::use(Value); | ||||||
|                 Select.execute(); |                 if(Select.execute()==1) { | ||||||
|  |  | ||||||
|                 if(Select.rowsExtracted()==1) { |  | ||||||
|                     Convert(RT,R); |                     Convert(RT,R); | ||||||
|                     if(Cache_) |  | ||||||
|                         Cache_->UpdateCache(R); |  | ||||||
|                     return true; |                     return true; | ||||||
|                 } |                 } | ||||||
|                 return false; |                 return false; | ||||||
| @@ -440,7 +376,7 @@ namespace ORM { | |||||||
|         typedef std::vector<std::string> StringVec; |         typedef std::vector<std::string> StringVec; | ||||||
|  |  | ||||||
|         template <  typename T, |         template <  typename T, | ||||||
|                 typename T0, typename T1> bool GR(field_name_t FieldName, T & R,T0 &V0, T1 &V1) { |                 typename T0, typename T1> bool GR(const char *FieldName, T & R,T0 &V0, T1 &V1) { | ||||||
|             try { |             try { | ||||||
|  |  | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
| @@ -449,7 +385,7 @@ namespace ORM { | |||||||
|                 Poco::Data::Statement   Select(Session); |                 Poco::Data::Statement   Select(Session); | ||||||
|                 RecordTuple RT; |                 RecordTuple RT; | ||||||
|  |  | ||||||
|                 std::string St = "select " + SelectFields_ + " from " + TableName_ |                 std::string St = "select " + SelectFields_ + " from " + DBName | ||||||
|                                 + " where " + FieldName[0] + "=? and " + FieldName[1] + "=?"  ; |                                 + " where " + FieldName[0] + "=? and " + FieldName[1] + "=?"  ; | ||||||
|                 Select  << ConvertParams(St) , |                 Select  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::into(RT), |                     Poco::Data::Keywords::into(RT), | ||||||
| @@ -474,15 +410,14 @@ namespace ORM { | |||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Select(Session); |                 Poco::Data::Statement   Select(Session); | ||||||
|                 RecordList RL; |                 RecordList RL; | ||||||
|                 std::string St = "select " + SelectFields_ + " from " + TableName_ + |                 std::string St = "select " + SelectFields_ + " from " + DBName + | ||||||
|                         (Where.empty() ? "" : " where " + Where) + OrderBy + |                         (Where.empty() ? "" : " where " + Where) + OrderBy + | ||||||
|                         ComputeRange(Offset, HowMany) ; |                         ComputeRange(Offset, HowMany) ; | ||||||
|  |  | ||||||
|                 Select  << St , |                 Select  << St , | ||||||
|                     Poco::Data::Keywords::into(RL); |                     Poco::Data::Keywords::into(RL); | ||||||
|                 Select.execute(); |  | ||||||
|  |  | ||||||
|                 if(Select.rowsExtracted()>0) { |                 if(Select.execute()>0) { | ||||||
|                     for(auto &i:RL) { |                     for(auto &i:RL) { | ||||||
|                         RecordType  R; |                         RecordType  R; | ||||||
|                         Convert(i, R); |                         Convert(i, R); | ||||||
| @@ -497,7 +432,7 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template <typename T> bool UpdateRecord(field_name_t FieldName, const T & Value,  const RecordType & R) { |         template <typename T> bool UpdateRecord( const char *FieldName, T & Value,  RecordType & R) { | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|  |  | ||||||
| @@ -508,15 +443,11 @@ namespace ORM { | |||||||
|  |  | ||||||
|                 Convert(R, RT); |                 Convert(R, RT); | ||||||
|  |  | ||||||
|                 auto tValue(Value); |                 std::string St = "update " + DBName + " set " + UpdateFields_ + " where " + FieldName + "=?" ; | ||||||
|  |  | ||||||
|                 std::string St = "update " + TableName_ + " set " + UpdateFields_ + " where " + FieldName + "=?" ; |  | ||||||
|                 Update  << ConvertParams(St) , |                 Update  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::use(RT), |                     Poco::Data::Keywords::use(RT), | ||||||
|                     Poco::Data::Keywords::use(tValue); |                     Poco::Data::Keywords::use(Value); | ||||||
|                 Update.execute(); |                 Update.execute(); | ||||||
|                 if(Cache_) |  | ||||||
|                     Cache_->UpdateCache(R); |  | ||||||
|                 return true; |                 return true; | ||||||
|             } catch (const Poco::Exception &E) { |             } catch (const Poco::Exception &E) { | ||||||
|                 Logger_.log(E); |                 Logger_.log(E); | ||||||
| @@ -524,32 +455,18 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template <typename T> bool ReplaceRecord(field_name_t FieldName, const T & Value,  RecordType & R) { |         template <typename T> bool GetNameAndDescription(const char *FieldName, T & Value, std::string & Name, std::string & Description ) { | ||||||
|             try { |  | ||||||
|                 if(Exists(FieldName, Value)) { |  | ||||||
|                     return UpdateRecord(FieldName,Value,R); |  | ||||||
|                 } |  | ||||||
|                 return CreateRecord(R); |  | ||||||
|             } catch (const Poco::Exception &E) { |  | ||||||
|                 Logger_.log(E); |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         template <typename T> bool GetNameAndDescription(field_name_t FieldName, const T & Value, std::string & Name, std::string & Description ) { |  | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Select(Session); |                 Poco::Data::Statement   Select(Session); | ||||||
|                 RecordTuple             RT; |                 RecordTuple             RT; | ||||||
|  |  | ||||||
|                 std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" ; |                 std::string St = "select " + SelectFields_ + " from " + DBName + " where " + FieldName + "=?" ; | ||||||
|                 RecordType R; |                 RecordType R; | ||||||
|                 auto tValue{Value}; |  | ||||||
|                 Select  << ConvertParams(St) , |                 Select  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::into(RT), |                 Poco::Data::Keywords::into(RT), | ||||||
|                     Poco::Data::Keywords::use(tValue); |                 Poco::Data::Keywords::use(Value); | ||||||
|  |  | ||||||
|                 if(Select.execute()==1) { |                 if(Select.execute()==1) { | ||||||
|                     Convert(RT,R); |                     Convert(RT,R); | ||||||
|                     Name = R.info.name; |                     Name = R.info.name; | ||||||
| @@ -563,21 +480,17 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template <typename T> bool DeleteRecord(field_name_t FieldName, const T & Value) { |         template <typename T> bool DeleteRecord( const char *FieldName, T Value) { | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|  |  | ||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Delete(Session); |                 Poco::Data::Statement   Delete(Session); | ||||||
|  |  | ||||||
|                 std::string St = "delete from " + TableName_ + " where " + FieldName + "=?" ; |                 std::string St = "delete from " + DBName + " where " + FieldName + "=?" ; | ||||||
|                 auto tValue{Value}; |  | ||||||
|  |  | ||||||
|                 Delete  << ConvertParams(St) , |                 Delete  << ConvertParams(St) , | ||||||
|                     Poco::Data::Keywords::use(tValue); |                     Poco::Data::Keywords::use(Value); | ||||||
|                 Delete.execute(); |                 Delete.execute(); | ||||||
|                 if(Cache_) |  | ||||||
|                     Cache_->Delete(FieldName, Value); |  | ||||||
|                 return true; |                 return true; | ||||||
|             } catch (const Poco::Exception &E) { |             } catch (const Poco::Exception &E) { | ||||||
|                 Logger_.log(E); |                 Logger_.log(E); | ||||||
| @@ -591,7 +504,7 @@ namespace ORM { | |||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Delete(Session); |                 Poco::Data::Statement   Delete(Session); | ||||||
|  |  | ||||||
|                 std::string St = "delete from " + TableName_ + " where " + WhereClause; |                 std::string St = "delete from " + DBName + " where " + WhereClause; | ||||||
|                 Delete  << St; |                 Delete  << St; | ||||||
|                 Delete.execute(); |                 Delete.execute(); | ||||||
|                 return true; |                 return true; | ||||||
| @@ -601,7 +514,7 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool Exists(field_name_t FieldName, const std::string & Value) { |         bool Exists(const char *FieldName, std::string & Value) { | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|  |  | ||||||
| @@ -615,15 +528,15 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool Iterate( std::function<bool(const RecordType &R)> F, const std::string & WhereClause = "" ) { |         bool Iterate( std::function<bool(const RecordType &R)> F) { | ||||||
|             try { |             try { | ||||||
|  |  | ||||||
|                 uint64_t    Offset=0; |                 uint64_t    Offset=1; | ||||||
|                 uint64_t    Batch=50; |                 uint64_t    Batch=50; | ||||||
|                 bool Done=false; |                 bool Done=false; | ||||||
|                 while(!Done) { |                 while(!Done) { | ||||||
|                     std::vector<RecordType> Records; |                     std::vector<RecordType> Records; | ||||||
|                     if(GetRecords(Offset,Batch,Records, WhereClause)) { |                     if(GetRecords(Offset,Batch,Records)) { | ||||||
|                         for(const auto &i:Records) { |                         for(const auto &i:Records) { | ||||||
|                             if(!F(i)) |                             if(!F(i)) | ||||||
|                                 return true; |                                 return true; | ||||||
| @@ -679,7 +592,7 @@ namespace ORM { | |||||||
|                 Poco::Data::Session     Session = Pool_.get(); |                 Poco::Data::Session     Session = Pool_.get(); | ||||||
|                 Poco::Data::Statement   Select(Session); |                 Poco::Data::Statement   Select(Session); | ||||||
|  |  | ||||||
|                 std::string st{"SELECT COUNT(*) FROM " + TableName_ + " " + (Where.empty() ? "" : (" where " + Where)) }; |                 std::string st{"SELECT COUNT(*) FROM " + DBName + " " + (Where.empty() ? "" : (" where " + Where)) }; | ||||||
|  |  | ||||||
|                 Select << st , |                 Select << st , | ||||||
|                     Poco::Data::Keywords::into(Cnt); |                     Poco::Data::Keywords::into(Cnt); | ||||||
| @@ -693,7 +606,7 @@ namespace ORM { | |||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template <typename X> bool ManipulateVectorMember( X T, field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID, bool Add) { |         template <typename X> bool ManipulateVectorMember( X T, const char *FieldName, std::string & ParentUUID, std::string & ChildUUID, bool Add) { | ||||||
|             try { |             try { | ||||||
|                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); |                 assert( FieldNames_.find(FieldName) != FieldNames_.end() ); | ||||||
|  |  | ||||||
| @@ -720,122 +633,89 @@ namespace ORM { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool RunScript(const std::vector<std::string> & Statements, bool IgnoreExceptions=true) { |         inline bool AddChild( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             try { |  | ||||||
|                 Poco::Data::Session     Session = Pool_.get(); |  | ||||||
|                 Poco::Data::Statement   Command(Session); |  | ||||||
|  |  | ||||||
|                 for(const auto &i:Statements) { |  | ||||||
|                     try { |  | ||||||
|                         Command << i, Poco::Data::Keywords::now; |  | ||||||
|                     } catch (const Poco::Exception &E) { |  | ||||||
|                         Logger_.log(E); |  | ||||||
|                         Logger_.error(Poco::format("The following statement '%s' generated an exception during a table upgrade. This maya or may not be a problem.", i)); |  | ||||||
|                     } |  | ||||||
|                     if(!IgnoreExceptions) { |  | ||||||
|                         return false; |  | ||||||
|                     } |  | ||||||
|                     Command.reset(Session); |  | ||||||
|                 } |  | ||||||
|                 return true; |  | ||||||
|             } catch (const Poco::Exception &E) { |  | ||||||
|                 Logger_.log(E); |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         virtual uint32_t Version() { |  | ||||||
|             return 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         virtual bool Upgrade(uint32_t from, uint32_t &to) { |  | ||||||
|             to = from; |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         inline bool AddChild(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |  | ||||||
|             return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteChild(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteChild( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddLocation(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddLocation( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteLocation(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteLocation( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddContact(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddContact( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteContact(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteContact( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddVenue(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddVenue( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteVenue(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteVenue( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddDevice(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddDevice( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteDevice(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteDevice( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddEntity(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddEntity( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteEntity(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteEntity( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddUser(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddUser( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DelUser(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DelUser( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddInUse(field_name_t FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { |         inline bool AddInUse(const char *FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { | ||||||
|             std::string FakeUUID{ Prefix + ":" + ChildUUID}; |             std::string FakeUUID{ Prefix + ":" + ChildUUID}; | ||||||
|             return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, true); |             return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteInUse(field_name_t FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { |         inline bool DeleteInUse(const char *FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { | ||||||
|             std::string FakeUUID{ Prefix + ":" + ChildUUID}; |             std::string FakeUUID{ Prefix + ":" + ChildUUID}; | ||||||
|             return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, false); |             return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteContact(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteContact(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddContact(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddContact(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool DeleteLocation(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool DeleteLocation(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, false); |             return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool AddLocation(field_name_t FieldName, std::string & ParentUUID, const std::string & ChildUUID) { |         inline bool AddLocation(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { | ||||||
|             return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, true); |             return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline bool GetInUse(field_name_t FieldName, const std::string & UUID, std::vector<std::string> & UUIDs ) { |         inline bool GetInUse(const char *FieldName, std::string & UUID, std::vector<std::string> & UUIDs ) { | ||||||
|             RecordType  R; |             RecordType  R; | ||||||
|             if(GetRecord(FieldName,UUID,R)) { |             if(GetRecord(FieldName,UUID,R)) { | ||||||
|                 UUIDs = R.inUse; |                 UUIDs = R.inUse; | ||||||
| @@ -845,41 +725,34 @@ namespace ORM { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { |         [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { | ||||||
|             if(From<1) From=0; |             if(From<1) From=1; | ||||||
|             switch(Type_) { |             switch(Type) { | ||||||
|                 case OpenWifi::DBType::sqlite: |                 case OpenWifi::DBType::sqlite: | ||||||
|                     return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) +  " "; |                     return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) +  " "; | ||||||
|                 case OpenWifi::DBType::pgsql: |                 case OpenWifi::DBType::pgsql: | ||||||
|                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; |                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; | ||||||
|                 case OpenWifi::DBType::mysql: |                 case OpenWifi::DBType::mysql: | ||||||
|                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; |                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; | ||||||
|                 default: |                 default: | ||||||
|                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; |                     return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::Logger & Logger() { return Logger_; } |         Poco::Logger & Logger() { return Logger_; } | ||||||
|  |  | ||||||
|         bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) { |  | ||||||
|             if(Cache_) |  | ||||||
|                 Cache_->Delete(FieldName, Value); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     protected: |  | ||||||
|         Poco::Data::SessionPool     &Pool_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         std::string                 TableName_; |  | ||||||
|         DBCache<RecordType>         *Cache_= nullptr; |  | ||||||
|     private: |     private: | ||||||
|         OpenWifi::DBType            Type_; |         OpenWifi::DBType            Type; | ||||||
|  |         std::string                 DBName; | ||||||
|         std::string                 CreateFields_; |         std::string                 CreateFields_; | ||||||
|         std::string                 SelectFields_; |         std::string                 SelectFields_; | ||||||
|         std::string                 SelectList_; |         std::string                 SelectList_; | ||||||
|         std::string                 UpdateFields_; |         std::string                 UpdateFields_; | ||||||
|         std::vector<std::string>    IndexCreation_; |         std::string                 IndexCreation; | ||||||
|         std::map<std::string,int>   FieldNames_; |         std::map<std::string,int>   FieldNames_; | ||||||
|  |         Poco::Data::SessionPool     &Pool_; | ||||||
|  |         Poco::Logger                &Logger_; | ||||||
|         std::string                 Prefix_; |         std::string                 Prefix_; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -5,7 +5,9 @@ | |||||||
| //	Created by Stephane Bourque on 2021-03-04. | //	Created by Stephane Bourque on 2021-03-04. | ||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
| #pragma once |  | ||||||
|  | #ifndef UCENTRALGW_UCENTRALPROTOCOL_H | ||||||
|  | #define UCENTRALGW_UCENTRALPROTOCOL_H | ||||||
|  |  | ||||||
| #include "Poco/String.h" | #include "Poco/String.h" | ||||||
|  |  | ||||||
| @@ -38,7 +40,6 @@ namespace OpenWifi::uCentralProtocol { | |||||||
| 	static const char * LOGLINES = "loglines"; | 	static const char * LOGLINES = "loglines"; | ||||||
| 	static const char * SEVERITY = "severity"; | 	static const char * SEVERITY = "severity"; | ||||||
| 	static const char * ACTIVE = "active"; | 	static const char * ACTIVE = "active"; | ||||||
| 	static const char * OVERRIDEDFS = "override_dfs"; |  | ||||||
| 	static const char * REBOOT = "reboot"; | 	static const char * REBOOT = "reboot"; | ||||||
| 	static const char * WHEN = "when"; | 	static const char * WHEN = "when"; | ||||||
| 	static const char * CONFIG = "config"; | 	static const char * CONFIG = "config"; | ||||||
| @@ -129,3 +130,5 @@ namespace OpenWifi::uCentralProtocol { | |||||||
| 			return ET_UNKNOWN; | 			return ET_UNKNOWN; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif // UCENTRALGW_UCENTRALPROTOCOL_H | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user