mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-11-03 20:27:45 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			v2.5.2
			...
			release/v2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					6a9b0f143e | ||
| 
						 | 
					736d981853 | ||
| 
						 | 
					9a27996d44 | 
							
								
								
									
										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_USERNAME: ucentral
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Checkout actions repo
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
      with:
 | 
			
		||||
        repository: Telecominfraproject/.github
 | 
			
		||||
        path: github
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
 | 
			
		||||
    - name: Build and push Docker image
 | 
			
		||||
      uses: ./github/composite-actions/docker-image-build
 | 
			
		||||
      with:
 | 
			
		||||
        image_name: owsec
 | 
			
		||||
        registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
			
		||||
        registry_user: ucentral
 | 
			
		||||
        registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
 | 
			
		||||
    - name: Build Docker image
 | 
			
		||||
      run: docker build -t wlan-cloud-owsec:${{ github.sha }} .
 | 
			
		||||
 | 
			
		||||
  trigger-testing:
 | 
			
		||||
    if: startsWith(github.ref, 'refs/pull/')
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: docker
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Get base branch name and set as output
 | 
			
		||||
      id: get_base_branch
 | 
			
		||||
    - name: Tag Docker image
 | 
			
		||||
      run: |
 | 
			
		||||
        echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
 | 
			
		||||
        echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
 | 
			
		||||
        TAGS="${{ github.sha }}"
 | 
			
		||||
 | 
			
		||||
    - name: Checkout actions repo
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
      with:
 | 
			
		||||
        repository: Telecominfraproject/.github
 | 
			
		||||
        path: github
 | 
			
		||||
        if [[ ${GITHUB_REF} == "refs/heads/"* ]]
 | 
			
		||||
        then
 | 
			
		||||
          CURRENT_TAG=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-')
 | 
			
		||||
          TAGS="$TAGS $CURRENT_TAG"
 | 
			
		||||
        else
 | 
			
		||||
          if [[ ${GITHUB_REF} == "refs/tags/"* ]]
 | 
			
		||||
          then
 | 
			
		||||
            CURRENT_TAG=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-')
 | 
			
		||||
            TAGS="$TAGS $CURRENT_TAG"
 | 
			
		||||
          else # PR build
 | 
			
		||||
            CURRENT_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
 | 
			
		||||
            TAGS="$TAGS $CURRENT_TAG"
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
    - name: Trigger testing of OpenWifi Docker Compose deployment and wait for result
 | 
			
		||||
      uses: ./github/composite-actions/trigger-workflow-and-wait
 | 
			
		||||
      env:
 | 
			
		||||
        BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }}
 | 
			
		||||
        OWGW_BASE_BRANCH: ${{ steps.get_base_branch.outputs.owgw_branch }}
 | 
			
		||||
        echo "Result tags: $TAGS"
 | 
			
		||||
 | 
			
		||||
        for tag in $TAGS; do
 | 
			
		||||
          docker tag wlan-cloud-owsec:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owsec:$tag
 | 
			
		||||
        done
 | 
			
		||||
 | 
			
		||||
    - name: Log into Docker registry
 | 
			
		||||
      if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main'
 | 
			
		||||
      uses: docker/login-action@v1
 | 
			
		||||
      with:
 | 
			
		||||
        owner: Telecominfraproject
 | 
			
		||||
        repo: wlan-testing
 | 
			
		||||
        workflow: ow_docker-compose.yml
 | 
			
		||||
        token: ${{ secrets.WLAN_TESTING_PAT }}
 | 
			
		||||
        ref: master
 | 
			
		||||
        inputs: '{"owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owgwui_version": "${{ env.BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "main", "owprovui_version": "main"}'
 | 
			
		||||
        registry: ${{ env.DOCKER_REGISTRY_URL }}
 | 
			
		||||
        username: ${{ env.DOCKER_REGISTRY_USERNAME }}
 | 
			
		||||
        password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
 | 
			
		||||
 | 
			
		||||
    - name: Push Docker images
 | 
			
		||||
      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
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -18,4 +18,3 @@ _deps
 | 
			
		||||
*.csr
 | 
			
		||||
/cmake-build/
 | 
			
		||||
/smake-build-debug/
 | 
			
		||||
test_scripts/curl/result.json
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.13)
 | 
			
		||||
project(owsec VERSION 2.5.0)
 | 
			
		||||
project(owsec VERSION 2.3.0)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 17)
 | 
			
		||||
 | 
			
		||||
@@ -20,32 +20,19 @@ endif()
 | 
			
		||||
 | 
			
		||||
# Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1
 | 
			
		||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build)
 | 
			
		||||
    file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM)
 | 
			
		||||
    file(READ build BUILD_NUM)
 | 
			
		||||
    if(BUILD_INCREMENT)
 | 
			
		||||
        MATH(EXPR BUILD_NUM "${BUILD_NUM}+1")
 | 
			
		||||
        file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
 | 
			
		||||
        file(WRITE build ${BUILD_NUM})
 | 
			
		||||
    endif()
 | 
			
		||||
else()
 | 
			
		||||
    set(BUILD_NUM 1)
 | 
			
		||||
    file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
 | 
			
		||||
    file(WRITE build ${BUILD_NUM})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
find_package(Git QUIET)
 | 
			
		||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
			
		||||
    execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
 | 
			
		||||
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
			
		||||
            RESULT_VARIABLE GIT_RESULT
 | 
			
		||||
            OUTPUT_VARIABLE GIT_HASH)
 | 
			
		||||
    if(NOT GIT_RESULT EQUAL "0")
 | 
			
		||||
        message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
 | 
			
		||||
    endif()
 | 
			
		||||
    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
 | 
			
		||||
 | 
			
		||||
set(BUILD_SHARED_LIBS 1)
 | 
			
		||||
 | 
			
		||||
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}")
 | 
			
		||||
add_definitions(-DTIP_SECURITY_SERVICE="1")
 | 
			
		||||
 | 
			
		||||
set(Boost_USE_STATIC_LIBS OFF)
 | 
			
		||||
@@ -55,7 +42,7 @@ find_package(Boost REQUIRED system)
 | 
			
		||||
find_package(OpenSSL REQUIRED)
 | 
			
		||||
find_package(ZLIB REQUIRED)
 | 
			
		||||
find_package(AWSSDK     REQUIRED COMPONENTS sns)
 | 
			
		||||
find_package(nlohmann_json  REQUIRED)
 | 
			
		||||
 | 
			
		||||
find_package(CppKafka REQUIRED)
 | 
			
		||||
find_package(PostgreSQL REQUIRED)
 | 
			
		||||
find_package(MySQL REQUIRED)
 | 
			
		||||
@@ -63,48 +50,35 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS
 | 
			
		||||
 | 
			
		||||
include_directories(/usr/local/include  /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
 | 
			
		||||
 | 
			
		||||
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
 | 
			
		||||
 | 
			
		||||
add_executable( owsec
 | 
			
		||||
        build
 | 
			
		||||
        src/ow_version.h.in
 | 
			
		||||
        src/framework/CountryCodes.h
 | 
			
		||||
        src/framework/KafkaTopics.h
 | 
			
		||||
        src/framework/MicroService.h
 | 
			
		||||
        src/framework/OpenWifiTypes.h
 | 
			
		||||
        src/framework/orm.h
 | 
			
		||||
        src/framework/RESTAPI_errors.h
 | 
			
		||||
        src/framework/RESTAPI_protocol.h
 | 
			
		||||
        src/framework/StorageClass.h
 | 
			
		||||
        src/framework/uCentral_Protocol.h
 | 
			
		||||
        src/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_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.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_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.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_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_subavatar_handler.cpp src/RESTAPI/RESTAPI_subavatar_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.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_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp src/RESTAPI/RESTAPI_validate_sub_token_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_subpreferences.cpp src/RESTAPI/RESTAPI_subpreferences.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_routers.cpp
 | 
			
		||||
        src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h
 | 
			
		||||
        src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp
 | 
			
		||||
        src/APIServers.cpp
 | 
			
		||||
        src/Daemon.h src/Daemon.cpp
 | 
			
		||||
        src/SpecialUserHelpers.h
 | 
			
		||||
        src/AuthService.h src/AuthService.cpp
 | 
			
		||||
        src/StorageService.cpp src/StorageService.h
 | 
			
		||||
        src/SMTPMailerService.cpp src/SMTPMailerService.h
 | 
			
		||||
@@ -112,17 +86,7 @@ add_executable( owsec
 | 
			
		||||
        src/MFAServer.cpp src/MFAServer.h
 | 
			
		||||
        src/SMS_provider_aws.cpp src/SMS_provider_aws.h
 | 
			
		||||
        src/SMS_provider.cpp src/SMS_provider.h
 | 
			
		||||
        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
 | 
			
		||||
        src/ActionLinkManager.cpp src/ActionLinkManager.h
 | 
			
		||||
        src/ACLProcessor.h
 | 
			
		||||
        src/framework/OpenWifiTypes.h
 | 
			
		||||
        src/storage/orm_users.cpp src/storage/orm_users.h
 | 
			
		||||
        src/storage/orm_tokens.cpp src/storage/orm_tokens.h
 | 
			
		||||
        src/storage/orm_preferences.cpp src/storage/orm_preferences.h
 | 
			
		||||
        src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
 | 
			
		||||
        src/storage/orm_avatar.cpp src/storage/orm_avatar.h
 | 
			
		||||
        src/SpecialUserHelpers.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h)
 | 
			
		||||
        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h)
 | 
			
		||||
 | 
			
		||||
if(NOT SMALL_BUILD)
 | 
			
		||||
    target_link_libraries(owsec PUBLIC
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,51 +1,16 @@
 | 
			
		||||
FROM alpine:3.15 AS build-base
 | 
			
		||||
FROM alpine AS builder
 | 
			
		||||
 | 
			
		||||
RUN apk add --update --no-cache \
 | 
			
		||||
    make cmake g++ git \
 | 
			
		||||
    unixodbc-dev postgresql-dev mariadb-dev \
 | 
			
		||||
    librdkafka-dev boost-dev openssl-dev \
 | 
			
		||||
    zlib-dev nlohmann-json \
 | 
			
		||||
    curl-dev
 | 
			
		||||
    openssl openssh \
 | 
			
		||||
    ncurses-libs \
 | 
			
		||||
    bash util-linux coreutils curl libcurl \
 | 
			
		||||
    make cmake gcc g++ libstdc++ libgcc git zlib-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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
WORKDIR /aws-sdk-cpp
 | 
			
		||||
@@ -58,31 +23,31 @@ RUN cmake .. -DBUILD_ONLY="sns;s3" \
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
ADD CMakeLists.txt build /owsec/
 | 
			
		||||
ADD cmake /owsec/cmake
 | 
			
		||||
ADD src /owsec/src
 | 
			
		||||
ADD .git /owsec/.git
 | 
			
		||||
 | 
			
		||||
COPY --from=poco-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
 | 
			
		||||
 | 
			
		||||
WORKDIR /owsec
 | 
			
		||||
RUN mkdir cmake-build
 | 
			
		||||
WORKDIR /owsec/cmake-build
 | 
			
		||||
RUN cmake .. \
 | 
			
		||||
          -Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
 | 
			
		||||
          -DBUILD_SHARED_LIBS=ON
 | 
			
		||||
RUN cmake ..
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
 | 
			
		||||
FROM alpine:3.15
 | 
			
		||||
FROM alpine
 | 
			
		||||
 | 
			
		||||
ENV OWSEC_USER=owsec \
 | 
			
		||||
    OWSEC_ROOT=/owsec-data \
 | 
			
		||||
@@ -94,27 +59,22 @@ RUN addgroup -S "$OWSEC_USER" && \
 | 
			
		||||
RUN mkdir /openwifi
 | 
			
		||||
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
 | 
			
		||||
    chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
 | 
			
		||||
 | 
			
		||||
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
 | 
			
		||||
    mariadb-connector-c libpq unixodbc postgresql-client
 | 
			
		||||
 | 
			
		||||
COPY readiness_check /readiness_check
 | 
			
		||||
COPY test_scripts/curl/cli /cli
 | 
			
		||||
RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl
 | 
			
		||||
COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec
 | 
			
		||||
COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/
 | 
			
		||||
COPY --from=builder /poco/cmake-build/lib/* /lib/
 | 
			
		||||
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /lib/
 | 
			
		||||
COPY --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 wwwassets /dist/wwwassets
 | 
			
		||||
COPY templates /dist/templates
 | 
			
		||||
COPY docker-entrypoint.sh /
 | 
			
		||||
COPY wait-for-postgres.sh /
 | 
			
		||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
			
		||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
			
		||||
 | 
			
		||||
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
 | 
			
		||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib/
 | 
			
		||||
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib/
 | 
			
		||||
COPY --from=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
 | 
			
		||||
COPY readiness_check /readiness_check
 | 
			
		||||
 | 
			
		||||
EXPOSE 16001 17001 16101
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								README.md
									
									
									
									
									
								
							@@ -98,40 +98,6 @@ to get a sample. The default is
 | 
			
		||||
### `authentication.oldpasswords`
 | 
			
		||||
The number of older passwords to keep. Default is 5.
 | 
			
		||||
 | 
			
		||||
### Changing default password
 | 
			
		||||
 | 
			
		||||
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
 | 
			
		||||
 | 
			
		||||
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
 | 
			
		||||
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
 | 
			
		||||
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
 | 
			
		||||
export OWSEC_DEFAULT_PASSWORD=weLoveWifi # default password __in cleartext__ from property 'authentication.default.password'
 | 
			
		||||
export OWSEC_NEW_PASSWORD=NewPass123% # new password that must be set for the user (must comply with 'authentication.validation.expression')
 | 
			
		||||
test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
CLI is also included in Docker image if you want to run it this way:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export OWSEC=openwifi.wlan.local:16001
 | 
			
		||||
#export FLAGS="-k"
 | 
			
		||||
export OWSEC_DEFAULT_USERNAME=root@system.com
 | 
			
		||||
export OWSEC_DEFAULT_PASSWORD=weLoveWifi
 | 
			
		||||
export OWSEC_NEW_PASSWORD=NewPass123%
 | 
			
		||||
docker run --rm -ti \
 | 
			
		||||
  --network=host \
 | 
			
		||||
  --env OWSEC \
 | 
			
		||||
  --env FLAGS \
 | 
			
		||||
  --env OWSEC_DEFAULT_USERNAME \
 | 
			
		||||
  --env OWSEC_DEFAULT_PASSWORD \
 | 
			
		||||
  --env OWSEC_NEW_PASSWORD \
 | 
			
		||||
  tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:main \
 | 
			
		||||
  /cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Kafka integration
 | 
			
		||||
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
 | 
			
		||||
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
 | 
			
		||||
@@ -218,7 +184,7 @@ 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,
 | 
			
		||||
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. 
 | 
			
		||||
 | 
			
		||||
```asm
 | 
			
		||||
@@ -252,13 +218,3 @@ mailer.loginmethod = login
 | 
			
		||||
mailer.port = 587
 | 
			
		||||
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"} \
 | 
			
		||||
  SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \
 | 
			
		||||
  SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
 | 
			
		||||
  SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \
 | 
			
		||||
  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:-""} \
 | 
			
		||||
  MAILER_ENABLED=${MAILER_ENABLED:-"false"} \
 | 
			
		||||
  MAILER_HOSTNAME=${MAILER_HOSTNAME:-"localhost"} \
 | 
			
		||||
  MAILER_USERNAME=${MAILER_USERNAME:-""} \
 | 
			
		||||
  MAILER_PASSWORD=${MAILER_PASSWORD:-""} \
 | 
			
		||||
  MAILER_HOSTNAME=${MAILER_HOSTNAME:-"smtp.gmail.com"} \
 | 
			
		||||
  MAILER_USERNAME=${MAILER_USERNAME:-"************************"} \
 | 
			
		||||
  MAILER_PASSWORD=${MAILER_PASSWORD:-"************************"} \
 | 
			
		||||
  MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \
 | 
			
		||||
  MAILER_PORT=${MAILER_PORT:-"587"} \
 | 
			
		||||
  MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,14 @@ name: owsec
 | 
			
		||||
version: 0.1.0
 | 
			
		||||
dependencies:
 | 
			
		||||
- name: postgresql
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  version: 10.9.2
 | 
			
		||||
  condition: postgresql.enabled
 | 
			
		||||
- name: mysql
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  version: 8.8.3
 | 
			
		||||
  condition: mysql.enabled
 | 
			
		||||
- name: mariadb
 | 
			
		||||
  repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
			
		||||
  repository: https://charts.bitnami.com/bitnami
 | 
			
		||||
  version: 9.4.2
 | 
			
		||||
  condition: mariadb.enabled
 | 
			
		||||
 
 | 
			
		||||
@@ -30,13 +30,3 @@ Create chart name and version as used by the chart label.
 | 
			
		||||
{{- define "owsec.chart" -}}
 | 
			
		||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
 | 
			
		||||
{{- end -}}
 | 
			
		||||
 | 
			
		||||
{{- define "owsec.ingress.apiVersion" -}}
 | 
			
		||||
  {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
 | 
			
		||||
      {{- print "networking.k8s.io/v1" -}}
 | 
			
		||||
  {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
 | 
			
		||||
    {{- print "networking.k8s.io/v1beta1" -}}
 | 
			
		||||
  {{- else -}}
 | 
			
		||||
    {{- print "extensions/v1beta1" -}}
 | 
			
		||||
  {{- end -}}
 | 
			
		||||
{{- end -}}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@ spec:
 | 
			
		||||
  replicas: {{ .Values.replicaCount }}
 | 
			
		||||
  strategy:
 | 
			
		||||
    type: {{ .Values.strategyType }}
 | 
			
		||||
  revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
 | 
			
		||||
  selector:
 | 
			
		||||
    matchLabels:
 | 
			
		||||
      app.kubernetes.io/name: {{ include "owsec.name" . }}
 | 
			
		||||
@@ -25,9 +24,6 @@ spec:
 | 
			
		||||
    metadata:
 | 
			
		||||
      annotations:
 | 
			
		||||
        checksum/config: {{ include "owsec.config" . | sha256sum }}
 | 
			
		||||
        {{- with .Values.podAnnotations }}
 | 
			
		||||
        {{- toYaml . | nindent 8 }}
 | 
			
		||||
        {{- end }}
 | 
			
		||||
      labels:
 | 
			
		||||
        app.kubernetes.io/name: {{ include "owsec.name" . }}
 | 
			
		||||
        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
			
		||||
@@ -36,16 +32,6 @@ spec:
 | 
			
		||||
        {{- end }}
 | 
			
		||||
    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:
 | 
			
		||||
 | 
			
		||||
        - name: owsec
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
{{- range $ingress, $ingressValue := .Values.ingresses }}
 | 
			
		||||
{{- if $ingressValue.enabled }}
 | 
			
		||||
---
 | 
			
		||||
apiVersion: {{ include "owsec.ingress.apiVersion" $root }}
 | 
			
		||||
apiVersion: extensions/v1beta1
 | 
			
		||||
kind: Ingress
 | 
			
		||||
metadata:
 | 
			
		||||
  name: {{ include "owsec.fullname" $root }}-{{ $ingress }}
 | 
			
		||||
@@ -36,25 +36,11 @@ spec:
 | 
			
		||||
      paths:
 | 
			
		||||
      {{- range $ingressValue.paths }}
 | 
			
		||||
        - path: {{ .path }}
 | 
			
		||||
          {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
 | 
			
		||||
          pathType: {{ .pathType | default "ImplementationSpecific" }}
 | 
			
		||||
          {{- end }}
 | 
			
		||||
          backend:
 | 
			
		||||
            {{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
 | 
			
		||||
            service:
 | 
			
		||||
              name: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
 | 
			
		||||
              port:
 | 
			
		||||
              {{- if kindIs "string" .servicePort }}
 | 
			
		||||
                name: {{ .servicePort }}
 | 
			
		||||
              {{- else }}
 | 
			
		||||
                number: {{ .servicePort }}
 | 
			
		||||
              {{- end }}
 | 
			
		||||
            {{- else }}
 | 
			
		||||
            serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
 | 
			
		||||
            servicePort: {{ .servicePort }}
 | 
			
		||||
      {{- end }}
 | 
			
		||||
  {{- end }}
 | 
			
		||||
  {{- end }}
 | 
			
		||||
 | 
			
		||||
{{- end }}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
# System
 | 
			
		||||
replicaCount: 1
 | 
			
		||||
strategyType: Recreate
 | 
			
		||||
revisionHistoryLimit: 2
 | 
			
		||||
 | 
			
		||||
nameOverride: ""
 | 
			
		||||
fullnameOverride: ""
 | 
			
		||||
@@ -9,20 +8,16 @@ fullnameOverride: ""
 | 
			
		||||
images:
 | 
			
		||||
  owsec:
 | 
			
		||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
 | 
			
		||||
    tag: v2.5.2
 | 
			
		||||
    tag: v2.3.0-RC2
 | 
			
		||||
    pullPolicy: Always
 | 
			
		||||
#    regcred:
 | 
			
		||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
			
		||||
#      username: username
 | 
			
		||||
#      password: password
 | 
			
		||||
  dockerize:
 | 
			
		||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize
 | 
			
		||||
    tag: 0.16.0
 | 
			
		||||
    pullPolicy: IfNotPresent
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
  owsec:
 | 
			
		||||
    type: ClusterIP
 | 
			
		||||
    type: LoadBalancer
 | 
			
		||||
    ports:
 | 
			
		||||
      restapi:
 | 
			
		||||
        servicePort: 16001
 | 
			
		||||
@@ -43,6 +38,7 @@ checks:
 | 
			
		||||
      exec:
 | 
			
		||||
        command:
 | 
			
		||||
          - /readiness_check
 | 
			
		||||
      failureThreshold: 1
 | 
			
		||||
 | 
			
		||||
ingresses:
 | 
			
		||||
  restapi:
 | 
			
		||||
@@ -54,7 +50,6 @@ ingresses:
 | 
			
		||||
    - restapi.chart-example.local
 | 
			
		||||
    paths:
 | 
			
		||||
    - path: /
 | 
			
		||||
      pathType: ImplementationSpecific
 | 
			
		||||
      serviceName: owsec
 | 
			
		||||
      servicePort: restapi
 | 
			
		||||
 | 
			
		||||
@@ -100,8 +95,6 @@ tolerations: []
 | 
			
		||||
 | 
			
		||||
affinity: {}
 | 
			
		||||
 | 
			
		||||
podAnnotations: {}
 | 
			
		||||
 | 
			
		||||
persistence:
 | 
			
		||||
  enabled: true
 | 
			
		||||
  # storageClassName: "-"
 | 
			
		||||
@@ -146,17 +139,11 @@ configProperties:
 | 
			
		||||
  authentication.default.access: master
 | 
			
		||||
  authentication.service.type: internal
 | 
			
		||||
  # Mailer
 | 
			
		||||
  mailer.enabled: "false"
 | 
			
		||||
  mailer.hostname: smtp.gmail.com
 | 
			
		||||
  mailer.sender: OpenWIFI
 | 
			
		||||
  mailer.loginmethod: login
 | 
			
		||||
  mailer.port: 587
 | 
			
		||||
  mailer.templates: $OWSEC_ROOT/persist/templates
 | 
			
		||||
  # SMS
 | 
			
		||||
  smssender.enabled: "false"
 | 
			
		||||
  smssender.provider: "aws"
 | 
			
		||||
  #smssender.aws.region: ""
 | 
			
		||||
  #smssender.twilio.phonenumber: ""
 | 
			
		||||
  # ALB
 | 
			
		||||
  alb.enable: "true"
 | 
			
		||||
  alb.port: 16101
 | 
			
		||||
@@ -196,9 +183,22 @@ configProperties:
 | 
			
		||||
  openwifi.system.uri.ui: https://localhost
 | 
			
		||||
  openwifi.system.commandchannel: /tmp/app_owsec
 | 
			
		||||
  # Logging
 | 
			
		||||
  logging.type: console
 | 
			
		||||
  logging.path: $OWSEC_ROOT/logs
 | 
			
		||||
  logging.level: debug
 | 
			
		||||
  logging.formatters.f1.class: PatternFormatter
 | 
			
		||||
  logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
 | 
			
		||||
  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
 | 
			
		||||
  # REST API
 | 
			
		||||
@@ -210,12 +210,6 @@ configProperties:
 | 
			
		||||
  # Mailer
 | 
			
		||||
  mailer.username: no-reply@arilia.com
 | 
			
		||||
  mailer.password: "**************************"
 | 
			
		||||
  # SMS
 | 
			
		||||
  #smssender.aws.secretkey: ""
 | 
			
		||||
  #smssender.aws.accesskey: ""
 | 
			
		||||
  #smssender.twilio.sid: ""
 | 
			
		||||
  #smssender.twilio.token: ""
 | 
			
		||||
  #
 | 
			
		||||
  # Storage
 | 
			
		||||
  ## PostgreSQL
 | 
			
		||||
  storage.type.postgresql.username: stephb
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ openapi: 3.0.1
 | 
			
		||||
info:
 | 
			
		||||
  title: uCentral Security API
 | 
			
		||||
  description: A process to manage security logins.
 | 
			
		||||
  version: 2.5.0
 | 
			
		||||
  version: 2.0.0
 | 
			
		||||
  license:
 | 
			
		||||
    name: BSD3
 | 
			
		||||
    url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | 
			
		||||
@@ -51,21 +51,6 @@ components:
 | 
			
		||||
            properties:
 | 
			
		||||
              ErrorCode:
 | 
			
		||||
                type: integer
 | 
			
		||||
                enum:
 | 
			
		||||
                  - 0     # Success
 | 
			
		||||
                  - 1     # PASSWORD_CHANGE_REQUIRED,
 | 
			
		||||
                  - 2     # INVALID_CREDENTIALS,
 | 
			
		||||
                  - 3     # PASSWORD_ALREADY_USED,
 | 
			
		||||
                  - 4     # USERNAME_PENDING_VERIFICATION,
 | 
			
		||||
                  - 5     # PASSWORD_INVALID,
 | 
			
		||||
                  - 6     # INTERNAL_ERROR,
 | 
			
		||||
                  - 7     # ACCESS_DENIED,
 | 
			
		||||
                  - 8     # INVALID_TOKEN
 | 
			
		||||
                  - 9     # EXPIRED_TOKEN
 | 
			
		||||
                  - 10    # RATE_LIMIT_EXCEEDED
 | 
			
		||||
                  - 11    # BAD_MFA_TRANSACTION
 | 
			
		||||
                  - 12    # MFA_FAILURE
 | 
			
		||||
                  - 13    # SECURITY_SERVICE_UNREACHABLE
 | 
			
		||||
              ErrorDetails:
 | 
			
		||||
                type: string
 | 
			
		||||
              ErrorDescription:
 | 
			
		||||
@@ -84,20 +69,8 @@ components:
 | 
			
		||||
              Code:
 | 
			
		||||
                type: integer
 | 
			
		||||
 | 
			
		||||
    BadRequest:
 | 
			
		||||
      description: The requested operation failed.
 | 
			
		||||
      content:
 | 
			
		||||
        application/json:
 | 
			
		||||
          schema:
 | 
			
		||||
            properties:
 | 
			
		||||
              ErrorCode:
 | 
			
		||||
                type: integer
 | 
			
		||||
              ErrorDetails:
 | 
			
		||||
                type: string
 | 
			
		||||
              ErrorDescription:
 | 
			
		||||
                type: integer
 | 
			
		||||
 | 
			
		||||
  schemas:
 | 
			
		||||
 | 
			
		||||
    WebTokenRequest:
 | 
			
		||||
      description: User Id and password.
 | 
			
		||||
      type: object
 | 
			
		||||
@@ -243,7 +216,7 @@ components:
 | 
			
		||||
          enum:
 | 
			
		||||
            - sms
 | 
			
		||||
            - email
 | 
			
		||||
            - authenticator
 | 
			
		||||
            - voice
 | 
			
		||||
 | 
			
		||||
    UserLoginLoginExtensions:
 | 
			
		||||
      type: object
 | 
			
		||||
@@ -252,8 +225,6 @@ components:
 | 
			
		||||
          type: array
 | 
			
		||||
          items:
 | 
			
		||||
            $ref: '#/components/schemas/MobilePhoneNumber'
 | 
			
		||||
        authenticatorSecret:
 | 
			
		||||
          type: string
 | 
			
		||||
        mfa:
 | 
			
		||||
          $ref: '#/components/schemas/MfaAuthInfo'
 | 
			
		||||
 | 
			
		||||
@@ -350,9 +321,6 @@ components:
 | 
			
		||||
        securityPolicyChange:
 | 
			
		||||
          type: integer
 | 
			
		||||
          format: int64
 | 
			
		||||
        modified:
 | 
			
		||||
          type: integer
 | 
			
		||||
          format: int64
 | 
			
		||||
        userTypeProprietaryInfo:
 | 
			
		||||
          $ref: '#/components/schemas/UserLoginLoginExtensions'
 | 
			
		||||
 | 
			
		||||
@@ -413,24 +381,6 @@ components:
 | 
			
		||||
        answer:
 | 
			
		||||
          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
 | 
			
		||||
@@ -675,22 +625,6 @@ components:
 | 
			
		||||
          items:
 | 
			
		||||
            $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
 | 
			
		||||
@@ -756,64 +690,6 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /suboauth2:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Authentication
 | 
			
		||||
      summary: Get access token - to be used as Bearer token header for all other API requests.
 | 
			
		||||
      operationId: getSubAccessToken
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: newPassword
 | 
			
		||||
          description: used when a user is trying to change her password. This will be the new password.
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: forgotPassword
 | 
			
		||||
          description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: requirements
 | 
			
		||||
          description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: resendMFACode
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: completeMFAChallenge
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
      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}:
 | 
			
		||||
    delete:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -839,31 +715,6 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $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:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -928,52 +779,6 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /subusers:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Subscribers
 | 
			
		||||
      summary: Retrieve a list of existing users as well as some information about them.
 | 
			
		||||
      operationId: getSubUsers
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: offset
 | 
			
		||||
          schema:
 | 
			
		||||
            type: integer
 | 
			
		||||
            format: int64
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: limit
 | 
			
		||||
          schema:
 | 
			
		||||
            type: integer
 | 
			
		||||
            format: int64
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          description: Selecting this option means the newest record will be returned. Use limit to select how many.
 | 
			
		||||
          name: filter
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          description: Return only the ids.
 | 
			
		||||
          name: idOnly
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
        - in: query
 | 
			
		||||
          description: Return only the ids.
 | 
			
		||||
          name: select
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            example: id1,id2,id3,id4,id5
 | 
			
		||||
          required: false
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/UserList'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /user/{id}:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -1078,110 +883,6 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /subuser/{id}:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Subscribers
 | 
			
		||||
      operationId: getSubUser
 | 
			
		||||
      summary: Retrieve the information for a single user.
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: id
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            format: uuid
 | 
			
		||||
          required: true
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/UserInfo'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
    delete:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Subscribers
 | 
			
		||||
      operationId: deleteSubUser
 | 
			
		||||
      summary: Delete a single user.
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: id
 | 
			
		||||
          schema:
 | 
			
		||||
            type: integer
 | 
			
		||||
            format: int64
 | 
			
		||||
          required: true
 | 
			
		||||
      responses:
 | 
			
		||||
        204:
 | 
			
		||||
          $ref: '#/components/responses/Success'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Subscribers
 | 
			
		||||
      operationId: createSubUser
 | 
			
		||||
      summary: Create a single user.
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: id
 | 
			
		||||
          #must be set to 0 for user creation
 | 
			
		||||
          schema:
 | 
			
		||||
            type: integer
 | 
			
		||||
            format: int64
 | 
			
		||||
          required: true
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: email_verification
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
      requestBody:
 | 
			
		||||
        description: User details (some fields are ignored during creation)
 | 
			
		||||
        content:
 | 
			
		||||
          application/json:
 | 
			
		||||
            schema:
 | 
			
		||||
              $ref: '#/components/schemas/UserInfo'
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/UserInfo'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
    put:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Subscribers
 | 
			
		||||
      operationId: updateSubUser
 | 
			
		||||
      summary: Modify a single user.
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: id
 | 
			
		||||
          schema:
 | 
			
		||||
            type: integer
 | 
			
		||||
            format: int64
 | 
			
		||||
          required: true
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: email_verification
 | 
			
		||||
          schema:
 | 
			
		||||
            type: boolean
 | 
			
		||||
          required: false
 | 
			
		||||
      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}:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -1352,138 +1053,6 @@ paths:
 | 
			
		||||
                    items:
 | 
			
		||||
                      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
 | 
			
		||||
@@ -1559,27 +1128,6 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $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:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -40,7 +40,6 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec
 | 
			
		||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
			
		||||
openwifi.service.key.password = mypassword
 | 
			
		||||
 | 
			
		||||
smssender.enabled = false
 | 
			
		||||
smssender.provider = aws
 | 
			
		||||
smssender.aws.secretkey = ***************************************
 | 
			
		||||
smssender.aws.accesskey = ***************************************
 | 
			
		||||
@@ -54,7 +53,6 @@ smssender.aws.region = **************
 | 
			
		||||
#
 | 
			
		||||
# Security Microservice Specific Section
 | 
			
		||||
#
 | 
			
		||||
mailer.enabled = false
 | 
			
		||||
mailer.hostname = smtp.gmail.com
 | 
			
		||||
mailer.username = ************************
 | 
			
		||||
mailer.password = ************************
 | 
			
		||||
@@ -86,7 +84,6 @@ openwifi.document.policy.access = /wwwassets/access_policy.html
 | 
			
		||||
openwifi.document.policy.password = /wwwassets/password_policy.html
 | 
			
		||||
openwifi.avatar.maxsize = 2000000
 | 
			
		||||
 | 
			
		||||
totp.issuer = OpenWiFi
 | 
			
		||||
#
 | 
			
		||||
# 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
 | 
			
		||||
@@ -119,12 +116,44 @@ storage.type.mysql.database = ucentral
 | 
			
		||||
storage.type.mysql.port = 3306
 | 
			
		||||
storage.type.mysql.connectiontimeout = 60
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
########################################################################
 | 
			
		||||
#
 | 
			
		||||
# Logging: please leave as is for now.
 | 
			
		||||
#
 | 
			
		||||
########################################################################
 | 
			
		||||
logging.type = file
 | 
			
		||||
logging.path = $OWSEC_ROOT/logs
 | 
			
		||||
logging.level = debug
 | 
			
		||||
logging.formatters.f1.class = PatternFormatter
 | 
			
		||||
logging.formatters.f1.pattern = %s: [%p] %t
 | 
			
		||||
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.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
 | 
			
		||||
#
 | 
			
		||||
mailer.enabled = ${MAILER_ENABLED}
 | 
			
		||||
mailer.hostname = ${MAILER_HOSTNAME}
 | 
			
		||||
mailer.username = ${MAILER_USERNAME}
 | 
			
		||||
mailer.password = ${MAILER_PASSWORD}
 | 
			
		||||
@@ -122,6 +110,37 @@ storage.type.mysql.connectiontimeout = 60
 | 
			
		||||
# Logging: please leave as is for now.
 | 
			
		||||
#
 | 
			
		||||
########################################################################
 | 
			
		||||
logging.type = console
 | 
			
		||||
logging.path = $OWSEC_ROOT/logs
 | 
			
		||||
logging.level = debug
 | 
			
		||||
logging.formatters.f1.class = PatternFormatter
 | 
			
		||||
logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
 | 
			
		||||
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
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if [[ "${READINESS_METHOD}" == "systeminfo" ]]
 | 
			
		||||
if [[ "${OWSEC_USERNAME}" == "" ]]
 | 
			
		||||
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
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
  if [[ "${OWSEC_PASSWORD}" == "" ]]
 | 
			
		||||
  then
 | 
			
		||||
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
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ "${READINESS_METHOD}" == "systeminfo" ]]
 | 
			
		||||
then
 | 
			
		||||
  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
 | 
			
		||||
  payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,84 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-11-12.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef OWSEC_ACLPROCESSOR_H
 | 
			
		||||
#define OWSEC_ACLPROCESSOR_H
 | 
			
		||||
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    class ACLProcessor {
 | 
			
		||||
    public:
 | 
			
		||||
        enum ACL_OPS {
 | 
			
		||||
            READ,
 | 
			
		||||
            MODIFY,
 | 
			
		||||
            DELETE,
 | 
			
		||||
            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) {
 | 
			
		||||
            //  rule 1
 | 
			
		||||
            if(User.id == Target.id && Op==DELETE)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            //  rule 2
 | 
			
		||||
            if(User.userRole==SecurityObjects::ROOT)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            //  rule 3
 | 
			
		||||
            if(User.id == Target.id)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            //  rule 4
 | 
			
		||||
            if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if(Op==CREATE) {
 | 
			
		||||
                if(User.userRole==SecurityObjects::ROOT)
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::ADMIN &&
 | 
			
		||||
                    (Target.userRole==SecurityObjects::ADMIN ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::ACCOUNTING &&
 | 
			
		||||
                    (Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR))
 | 
			
		||||
                    return true;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //OWSEC_ACLPROCESSOR_H
 | 
			
		||||
							
								
								
									
										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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,97 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-11-08.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "ActionLinkManager.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    int ActionLinkManager::Start() {
 | 
			
		||||
        if(!Running_)
 | 
			
		||||
            Thr_.start(*this);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ActionLinkManager::Stop() {
 | 
			
		||||
        if(Running_) {
 | 
			
		||||
            Running_ = false;
 | 
			
		||||
            Thr_.wakeUp();
 | 
			
		||||
            Thr_.join();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ActionLinkManager::run() {
 | 
			
		||||
        Running_ = true ;
 | 
			
		||||
 | 
			
		||||
        while(Running_) {
 | 
			
		||||
            Poco::Thread::trySleep(2000);
 | 
			
		||||
            if(!Running_)
 | 
			
		||||
                break;
 | 
			
		||||
            std::vector<SecurityObjects::ActionLink>    Links;
 | 
			
		||||
            {
 | 
			
		||||
                std::lock_guard G(Mutex_);
 | 
			
		||||
                StorageService()->ActionLinksDB().GetActions(Links);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(Links.empty())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            for(auto &i:Links) {
 | 
			
		||||
                if(!Running_)
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                SecurityObjects::UserInfo UInfo;
 | 
			
		||||
                if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
 | 
			
		||||
                    i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
 | 
			
		||||
                    StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
			
		||||
                    continue;
 | 
			
		||||
                } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
 | 
			
		||||
                            i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
 | 
			
		||||
                    StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                switch(i.action) {
 | 
			
		||||
                    case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
 | 
			
		||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
 | 
			
		||||
                                Logger().information(Poco::format("Send password reset link to %s",UInfo.email));
 | 
			
		||||
                            }
 | 
			
		||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
 | 
			
		||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, 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);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-11-08.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
#define OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    class ActionLinkManager : public SubSystemServer, Poco::Runnable {
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
/*        enum Actions {
 | 
			
		||||
            FORGOT_PASSWORD,
 | 
			
		||||
            VERIFY_EMAIL,
 | 
			
		||||
            SUB_FORGOT_PASSWORD,
 | 
			
		||||
            SUB_VERIFY_EMAIL
 | 
			
		||||
        };
 | 
			
		||||
*/
 | 
			
		||||
        static ActionLinkManager * instance() {
 | 
			
		||||
            static auto * instance_ = new ActionLinkManager;
 | 
			
		||||
            return instance_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int Start() final;
 | 
			
		||||
        void Stop() final;
 | 
			
		||||
        void run();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        Poco::Thread        Thr_;
 | 
			
		||||
        std::atomic_bool    Running_ = false;
 | 
			
		||||
 | 
			
		||||
        ActionLinkManager() noexcept:
 | 
			
		||||
            SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
 | 
			
		||||
                {
 | 
			
		||||
                }
 | 
			
		||||
    };
 | 
			
		||||
    inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
#include "Poco/Net/OAuth20Credentials.h"
 | 
			
		||||
#include "Poco/JWT/Token.h"
 | 
			
		||||
#include "Poco/JWT/Signer.h"
 | 
			
		||||
#include "Poco/StringTokenizer.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
@@ -22,6 +21,7 @@
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class AuthService *AuthService::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
    AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
 | 
			
		||||
		switch (C) {
 | 
			
		||||
@@ -45,162 +45,100 @@ namespace OpenWifi {
 | 
			
		||||
    int AuthService::Start() {
 | 
			
		||||
		Signer_.setRSAKey(MicroService::instance().Key());
 | 
			
		||||
		Signer_.addAllAlgorithms();
 | 
			
		||||
		Logger().notice("Starting...");
 | 
			
		||||
		Logger_.notice("Starting...");
 | 
			
		||||
        Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true);
 | 
			
		||||
        DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password","");
 | 
			
		||||
        DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username","");
 | 
			
		||||
        Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal");
 | 
			
		||||
        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);
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 )
 | 
			
		||||
    {
 | 
			
		||||
        if(!Secure_)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        std::lock_guard		Guard(Mutex_);
 | 
			
		||||
        Expired = false;
 | 
			
		||||
		try {
 | 
			
		||||
 | 
			
		||||
		std::string CallToken;
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			Poco::Net::OAuth20Credentials Auth(Request);
 | 
			
		||||
 | 
			
		||||
			if (Auth.getScheme() == "Bearer") {
 | 
			
		||||
				CallToken = Auth.getBearerToken();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            if(CallToken.empty()) {
 | 
			
		||||
                return false;
 | 
			
		||||
		} catch(const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
            SecurityObjects::WebToken   WT;
 | 
			
		||||
            uint64_t                    RevocationDate=0;
 | 
			
		||||
            std::string                 UserId;
 | 
			
		||||
            if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
                if(RevocationDate!=0)
 | 
			
		||||
		if(!CallToken.empty()) {
 | 
			
		||||
		    if(StorageService()->IsTokenRevoked(CallToken))
 | 
			
		||||
		        return false;
 | 
			
		||||
                Expired = (WT.created_ + WT.expires_in_) < time(nullptr);
 | 
			
		||||
                if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) {
 | 
			
		||||
                    UInfo.webtoken = WT;
 | 
			
		||||
		    auto Client = UserCache_.find(CallToken);
 | 
			
		||||
		    if( Client == UserCache_.end() )
 | 
			
		||||
		        return ValidateToken(CallToken, CallToken, UInfo);
 | 
			
		||||
 | 
			
		||||
		    if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
 | 
			
		||||
		        SessionToken = CallToken;
 | 
			
		||||
		        UInfo = Client->second ;
 | 
			
		||||
		        return true;
 | 
			
		||||
		    }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
		} catch(const Poco::Exception &E) {
 | 
			
		||||
		    Logger().log(E);
 | 
			
		||||
		}
 | 
			
		||||
		    UserCache_.erase(CallToken);
 | 
			
		||||
		    StorageService()->RevokeToken(CallToken);
 | 
			
		||||
		    return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
		return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::DeleteUserFromCache(const std::string &UserName) {
 | 
			
		||||
        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;
 | 
			
		||||
        for(auto i=UserCache_.begin();i!=UserCache_.end();) {
 | 
			
		||||
            if (i->second.userinfo.email==UserName) {
 | 
			
		||||
                Logout(i->first, false);
 | 
			
		||||
                i = UserCache_.erase(i);
 | 
			
		||||
            } else {
 | 
			
		||||
                ++i;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            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) {
 | 
			
		||||
        StorageService()->UserTokenDB().RevokeToken(Token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void AuthService::RevokeSubToken(std::string & Token) {
 | 
			
		||||
        StorageService()->SubTokenDB().RevokeToken(Token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::DeleteUserFromCache(const std::string &Id) {
 | 
			
		||||
        return StorageService()->UserTokenDB().DeleteRecordsFromCache("userName",Id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::DeleteSubUserFromCache(const std::string &Id) {
 | 
			
		||||
        return StorageService()->SubTokenDB().DeleteRecordsFromCache("userName",Id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        return std::regex_match(Password, PasswordValidation_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::ValidateSubPassword(const std::string &Password) {
 | 
			
		||||
        return std::regex_match(Password, SubPasswordValidation_);
 | 
			
		||||
    }
 | 
			
		||||
    void AuthService::Logout(const std::string &token, bool EraseFromCache) {
 | 
			
		||||
		std::lock_guard		Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		if(EraseFromCache)
 | 
			
		||||
		    UserCache_.erase(token);
 | 
			
		||||
 | 
			
		||||
    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(),
 | 
			
		||||
            std::string Tmp{token};
 | 
			
		||||
            StorageService()->RevokeToken(Tmp);
 | 
			
		||||
            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_);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            auto tToken{Token};
 | 
			
		||||
            StorageService()->UserTokenDB().DeleteRecord("token",tToken);
 | 
			
		||||
            StorageService()->LoginDB().AddLogout(Token);
 | 
			
		||||
        } catch (const Poco::Exception &E) {
 | 
			
		||||
            Logger().log(E);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void AuthService::SubLogout(const std::string &Token, 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);
 | 
			
		||||
            Logger_.log(E);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -230,6 +168,28 @@ namespace OpenWifi {
 | 
			
		||||
		return JWT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo  ) {
 | 
			
		||||
        std::lock_guard		Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
            auto E = UserCache_.find(SessionToken);
 | 
			
		||||
            if(E == UserCache_.end()) {
 | 
			
		||||
                if(StorageService()->GetToken(SessionToken,UInfo)) {
 | 
			
		||||
                    if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
 | 
			
		||||
                        UserCache_[UInfo.webtoken.access_token_] = UInfo;
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                UInfo = E->second;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
		} catch (const Poco::Exception &E ) {
 | 
			
		||||
			Logger_.log(E);
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard		Guard(Mutex_);
 | 
			
		||||
@@ -240,170 +200,50 @@ namespace OpenWifi {
 | 
			
		||||
        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.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()->UserDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
        StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
 | 
			
		||||
        UserCache_[UInfo.webtoken.access_token_] = UInfo;
 | 
			
		||||
        StorageService()->SetLastLogin(UInfo.userinfo.Id);
 | 
			
		||||
        StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_,
 | 
			
		||||
                            UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
 | 
			
		||||
                                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) {
 | 
			
		||||
        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()))
 | 
			
		||||
        auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword);
 | 
			
		||||
        for (auto const &i:UInfo.lastPasswords) {
 | 
			
		||||
            if (i == NewPasswordHash) {
 | 
			
		||||
                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.lastPasswords.push_back(NewPasswordHash);
 | 
			
		||||
        UInfo.currentPassword = NewPasswordHash;
 | 
			
		||||
        UInfo.changePassword = false;
 | 
			
		||||
        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() {
 | 
			
		||||
        auto start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
        return std::to_string(start.time_since_epoch().count());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) {
 | 
			
		||||
        std::string UName = Poco::trim(Poco::toLower(UserName));
 | 
			
		||||
        auto Salt = GetMeSomeSalt();
 | 
			
		||||
        SHA2_.update(Salt + Password + UName );
 | 
			
		||||
        return Salt + "|" + Utils::ToHex(SHA2_.digest());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::ValidatePasswordHash(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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 )
 | 
			
		||||
    AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard		Guard(Mutex_);
 | 
			
		||||
        SecurityObjects::AclTemplate	ACL;
 | 
			
		||||
 | 
			
		||||
        Poco::toLowerInPlace(UserName);
 | 
			
		||||
        auto PasswordHash = ComputePasswordHash(UserName, Password);
 | 
			
		||||
 | 
			
		||||
        if(StorageService()->UserDB().GetUserByEmail(UserName,UInfo.userinfo)) {
 | 
			
		||||
        if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
 | 
			
		||||
            if(UInfo.userinfo.waitingForEmailCheck) {
 | 
			
		||||
                return USERNAME_PENDING_VERIFICATION;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
 | 
			
		||||
            if(PasswordHash != UInfo.userinfo.currentPassword) {
 | 
			
		||||
                return INVALID_CREDENTIALS;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -423,89 +263,61 @@ namespace OpenWifi {
 | 
			
		||||
                }
 | 
			
		||||
                UInfo.userinfo.lastPasswordChange = std::time(nullptr);
 | 
			
		||||
                UInfo.userinfo.changePassword = false;
 | 
			
		||||
                UInfo.userinfo.modified = std::time(nullptr);
 | 
			
		||||
                StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo);
 | 
			
		||||
                StorageService()->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()->UserDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
            StorageService()->SetLastLogin(UInfo.userinfo.Id);
 | 
			
		||||
            CreateToken(UserName, UInfo );
 | 
			
		||||
 | 
			
		||||
            return SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return INVALID_CREDENTIALS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
 | 
			
		||||
        if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
 | 
			
		||||
        {
 | 
			
		||||
        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 );
 | 
			
		||||
 | 
			
		||||
            ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
 | 
			
		||||
            UInfo.webtoken.acl_template_ = ACL;
 | 
			
		||||
            UInfo.userinfo.email = DefaultUserName_;
 | 
			
		||||
            UInfo.userinfo.currentPassword = DefaultPassword_;
 | 
			
		||||
            UInfo.userinfo.name = DefaultUserName_;
 | 
			
		||||
            UInfo.userinfo.userRole = SecurityObjects::ROOT;
 | 
			
		||||
            CreateToken(UserName, UInfo );
 | 
			
		||||
            return SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return INVALID_CREDENTIALS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
 | 
			
		||||
    std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) {
 | 
			
		||||
        std::string UName = Poco::trim(Poco::toLower(UserName));
 | 
			
		||||
        SHA2_.update(Password + UName);
 | 
			
		||||
        return Utils::ToHex(SHA2_.digest());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) {
 | 
			
		||||
        SecurityObjects::UserInfo   UInfo;
 | 
			
		||||
 | 
			
		||||
        if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) {
 | 
			
		||||
        if(StorageService()->GetUserByEmail(Email,UInfo)) {
 | 
			
		||||
            switch (Reason) {
 | 
			
		||||
 | 
			
		||||
                case FORGOT_PASSWORD: {
 | 
			
		||||
                        MessageAttributes Attrs;
 | 
			
		||||
 | 
			
		||||
                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
                        Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
                        Attrs[LOGO] = "logo.jpg";
 | 
			
		||||
                        Attrs[SUBJECT] = "Password reset link";
 | 
			
		||||
                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
 | 
			
		||||
                        Attrs[ACTION_LINK] =
 | 
			
		||||
                                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
 | 
			
		||||
                        SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case EMAIL_VERIFICATION: {
 | 
			
		||||
                        MessageAttributes Attrs;
 | 
			
		||||
 | 
			
		||||
                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
                        Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
                        Attrs[LOGO] = "logo.jpg";
 | 
			
		||||
                        Attrs[SUBJECT] = "EMail Address Verification";
 | 
			
		||||
                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
 | 
			
		||||
                        Attrs[ACTION_LINK] =
 | 
			
		||||
                                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
 | 
			
		||||
                        SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
 | 
			
		||||
                        UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -514,113 +326,33 @@ namespace OpenWifi {
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        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) {
 | 
			
		||||
        SecurityObjects::ActionLink A;
 | 
			
		||||
        MessageAttributes Attrs;
 | 
			
		||||
 | 
			
		||||
        A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
 | 
			
		||||
        A.userId = UInfo.email;
 | 
			
		||||
        A.id = MicroService::CreateUUID();
 | 
			
		||||
        A.created = std::time(nullptr);
 | 
			
		||||
        A.expires = A.created + 24*60*60;
 | 
			
		||||
        A.userAction = true;
 | 
			
		||||
        StorageService()->ActionLinksDB().CreateAction(A);
 | 
			
		||||
        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
        Attrs[LOGO] = "logo.jpg";
 | 
			
		||||
        Attrs[SUBJECT] = "EMail Address Verification";
 | 
			
		||||
        Attrs[ACTION_LINK] =
 | 
			
		||||
                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
 | 
			
		||||
        SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
 | 
			
		||||
        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;
 | 
			
		||||
        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) {
 | 
			
		||||
        std::lock_guard G(Mutex_);
 | 
			
		||||
        Expired = false;
 | 
			
		||||
        auto It = UserCache_.find(Token);
 | 
			
		||||
 | 
			
		||||
        std::string TToken{Token}, UserId;
 | 
			
		||||
        SecurityObjects::WebToken   WT;
 | 
			
		||||
        uint64_t RevocationDate=0;
 | 
			
		||||
        if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
            if(RevocationDate!=0)
 | 
			
		||||
        if(It==UserCache_.end())
 | 
			
		||||
            return false;
 | 
			
		||||
            Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr);
 | 
			
		||||
            if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) {
 | 
			
		||||
                WebToken = WT;
 | 
			
		||||
        WebToken = It->second.webtoken;
 | 
			
		||||
        UserInfo = It->second.userinfo;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return IsValidSubToken(Token, WebToken, UserInfo, Expired);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
 | 
			
		||||
        std::lock_guard G(Mutex_);
 | 
			
		||||
        Expired = false;
 | 
			
		||||
 | 
			
		||||
        std::string TToken{Token}, UserId;
 | 
			
		||||
        SecurityObjects::WebToken   WT;
 | 
			
		||||
        uint64_t RevocationDate=0;
 | 
			
		||||
        if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
            if(RevocationDate!=0)
 | 
			
		||||
                return false;
 | 
			
		||||
            Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr);
 | 
			
		||||
            if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) {
 | 
			
		||||
                WebToken = WT;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}  // end of namespace
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
#include "Poco/SHA2Engine.h"
 | 
			
		||||
#include "Poco/Crypto/DigestEngine.h"
 | 
			
		||||
#include "Poco/HMACEngine.h"
 | 
			
		||||
#include "Poco/ExpireLRUCache.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
@@ -36,6 +35,16 @@ namespace OpenWifi{
 | 
			
		||||
            CUSTOM
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        enum AUTH_ERROR {
 | 
			
		||||
            SUCCESS,
 | 
			
		||||
            PASSWORD_CHANGE_REQUIRED,
 | 
			
		||||
            INVALID_CREDENTIALS,
 | 
			
		||||
            PASSWORD_ALREADY_USED,
 | 
			
		||||
            USERNAME_PENDING_VERIFICATION,
 | 
			
		||||
            PASSWORD_INVALID,
 | 
			
		||||
            INTERNAL_ERROR
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        enum EMAIL_REASON {
 | 
			
		||||
            FORGOT_PASSWORD,
 | 
			
		||||
            EMAIL_VERIFICATION
 | 
			
		||||
@@ -44,87 +53,51 @@ namespace OpenWifi{
 | 
			
		||||
        static ACCESS_TYPE IntToAccessType(int C);
 | 
			
		||||
        static int AccessTypeToInt(ACCESS_TYPE T);
 | 
			
		||||
 | 
			
		||||
        static auto instance() {
 | 
			
		||||
            static auto instance_ = new AuthService;
 | 
			
		||||
        static AuthService *instance() {
 | 
			
		||||
            if (instance_ == nullptr) {
 | 
			
		||||
                instance_ = new AuthService;
 | 
			
		||||
            }
 | 
			
		||||
            return instance_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int Start() override;
 | 
			
		||||
        void Stop() override;
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
 | 
			
		||||
        [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
 | 
			
		||||
        [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
 | 
			
		||||
        [[nodiscard]] AUTH_ERROR Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo );
 | 
			
		||||
        void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
        [[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo  );
 | 
			
		||||
        [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
			
		||||
        [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
			
		||||
        void Logout(const std::string &token, bool EraseFromCache=true);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
 | 
			
		||||
        [[nodiscard]] 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 ValidateSubPassword(const std::string &pwd);
 | 
			
		||||
 | 
			
		||||
        [[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]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo);
 | 
			
		||||
        [[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
 | 
			
		||||
        [[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 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 ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo  );
 | 
			
		||||
        [[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password);
 | 
			
		||||
        [[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]] 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 VerifySubEmail(SecurityObjects::UserInfo &UInfo);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
 | 
			
		||||
        [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
 | 
			
		||||
        [[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason);
 | 
			
		||||
        [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
 | 
			
		||||
        [[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 RevokeSubToken(std::string & Token);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] static inline const std::string GetLogoAssetURI() {
 | 
			
		||||
            return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] static inline const std::string GetLogoAssetFileName() {
 | 
			
		||||
            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:
 | 
			
		||||
		static AuthService *instance_;
 | 
			
		||||
		bool    			Secure_ = false ;
 | 
			
		||||
		std::string     	DefaultUserName_;
 | 
			
		||||
		std::string			DefaultPassword_;
 | 
			
		||||
		std::string     	Mechanism_;
 | 
			
		||||
		Poco::JWT::Signer	Signer_;
 | 
			
		||||
		Poco::SHA2Engine	SHA2_;
 | 
			
		||||
 | 
			
		||||
		std::string         AccessPolicy_;
 | 
			
		||||
		std::string         PasswordPolicy_;
 | 
			
		||||
		std::string         SubAccessPolicy_;
 | 
			
		||||
		std::string         SubPasswordPolicy_;
 | 
			
		||||
		SecurityObjects::UserInfoCache UserCache_;
 | 
			
		||||
        std::string          PasswordValidationStr_;
 | 
			
		||||
        std::string         SubPasswordValidationStr_;
 | 
			
		||||
		std::regex          PasswordValidation_;
 | 
			
		||||
        std::regex          SubPasswordValidation_;
 | 
			
		||||
 | 
			
		||||
		uint64_t            TokenAging_ = 30 * 24 * 60 * 60;
 | 
			
		||||
        uint64_t            HowManyOldPassword_=5;
 | 
			
		||||
 | 
			
		||||
@@ -152,13 +125,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 ) {
 | 
			
		||||
        if(Sub)
 | 
			
		||||
            return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired );
 | 
			
		||||
        else
 | 
			
		||||
            return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
 | 
			
		||||
    [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
 | 
			
		||||
        return AuthService()->IsAuthorized(Request, SessionToken, UInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // end of namespace
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,6 @@
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "ActionLinkManager.h"
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class Daemon *Daemon::instance_ = nullptr;
 | 
			
		||||
@@ -46,10 +44,7 @@ namespace OpenWifi {
 | 
			
		||||
                                   SubSystemVec{
 | 
			
		||||
                                           StorageService(),
 | 
			
		||||
                                           SMSSender(),
 | 
			
		||||
                                           ActionLinkManager(),
 | 
			
		||||
                                           SMTPMailerService(),
 | 
			
		||||
                                           RESTAPI_RateLimiter(),
 | 
			
		||||
                                           TotpCache(),
 | 
			
		||||
                                           AuthService()
 | 
			
		||||
                                   });
 | 
			
		||||
        }
 | 
			
		||||
@@ -58,6 +53,8 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void Daemon::initialize() {
 | 
			
		||||
        AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
			
		||||
        AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
 | 
			
		||||
        PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MicroServicePostInitialization() {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
#include "Poco/Crypto/CipherFactory.h"
 | 
			
		||||
#include "Poco/Crypto/Cipher.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/OpenWifiTypes.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
@@ -43,9 +44,13 @@ namespace OpenWifi {
 | 
			
		||||
        void initialize();
 | 
			
		||||
        static Daemon *instance();
 | 
			
		||||
        inline const std::string & AssetDir() { return AssetDir_; }
 | 
			
		||||
        inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
 | 
			
		||||
        inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
 | 
			
		||||
    private:
 | 
			
		||||
        static Daemon 		*instance_;
 | 
			
		||||
        std::string         AssetDir_;
 | 
			
		||||
        std::string         PasswordPolicy_;
 | 
			
		||||
        std::string         AccessPolicy_;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline Daemon * Daemon() { return Daemon::instance(); }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,11 +6,11 @@
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    class MFAServer * MFAServer::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
    int MFAServer::Start() {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -27,12 +27,11 @@ namespace OpenWifi {
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        std::string Challenge = MakeChallenge();
 | 
			
		||||
        std::string uuid = MicroService::CreateUUID();
 | 
			
		||||
        std::string uuid = MicroService::instance().CreateUUID();
 | 
			
		||||
        uint64_t Created = std::time(nullptr);
 | 
			
		||||
 | 
			
		||||
        ChallengeStart.set("uuid",uuid);
 | 
			
		||||
        ChallengeStart.set("created", Created);
 | 
			
		||||
        ChallengeStart.set("question", "mfa challenge");
 | 
			
		||||
        ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
 | 
			
		||||
 | 
			
		||||
        Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
 | 
			
		||||
@@ -40,18 +39,18 @@ namespace OpenWifi {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.";
 | 
			
		||||
            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;
 | 
			
		||||
            Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
 | 
			
		||||
            Attrs[LOGO] = AuthService::GetLogoAssetURI();
 | 
			
		||||
            Attrs[LOGO] = "logo.jpg";
 | 
			
		||||
            Attrs[SUBJECT] = "Login validation code";
 | 
			
		||||
            Attrs[CHALLENGE_CODE] = Challenge;
 | 
			
		||||
            return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
 | 
			
		||||
        } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -73,17 +72,11 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
        auto uuid = ChallengeResponse->get("uuid").toString();
 | 
			
		||||
        auto Hint = Cache_.find(uuid);
 | 
			
		||||
        if(Hint == end(Cache_)) {
 | 
			
		||||
        if(Hint == end(Cache_))
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto answer = ChallengeResponse->get("answer").toString();
 | 
			
		||||
        std::string Expecting;
 | 
			
		||||
        if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) {
 | 
			
		||||
            if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if(Hint->second.Answer!=answer) {
 | 
			
		||||
        if(Hint->second.Answer!=answer) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -93,15 +86,12 @@ namespace OpenWifi {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MFAServer::MethodEnabled(const std::string &Method) {
 | 
			
		||||
        if(Method==MFAMETHODS::SMS)
 | 
			
		||||
        if(Method=="sms")
 | 
			
		||||
            return SMSSender()->Enabled();
 | 
			
		||||
 | 
			
		||||
        if(Method==MFAMETHODS::EMAIL)
 | 
			
		||||
        if(Method=="email")
 | 
			
		||||
            return SMTPMailerService()->Enabled();
 | 
			
		||||
 | 
			
		||||
        if(Method==MFAMETHODS::AUTHENTICATOR)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,17 +10,6 @@
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
        SecurityObjects::UserInfoAndPolicy  UInfo;
 | 
			
		||||
        std::string                         Answer;
 | 
			
		||||
@@ -28,31 +17,31 @@ namespace OpenWifi {
 | 
			
		||||
        std::string                         Method;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache;
 | 
			
		||||
 | 
			
		||||
    class MFAServer : public SubSystemServer{
 | 
			
		||||
    public:
 | 
			
		||||
        int Start() override;
 | 
			
		||||
        void Stop() override;
 | 
			
		||||
        static auto instance() {
 | 
			
		||||
            static auto instance_ = new MFAServer;
 | 
			
		||||
        static MFAServer *instance() {
 | 
			
		||||
            if (instance_ == nullptr) {
 | 
			
		||||
                instance_ = new MFAServer;
 | 
			
		||||
            }
 | 
			
		||||
            return instance_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
 | 
			
		||||
        bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
        static bool MethodEnabled(const std::string &Method);
 | 
			
		||||
        bool MethodEnabled(const std::string &Method);
 | 
			
		||||
        bool ResendCode(const std::string &uuid);
 | 
			
		||||
        static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
			
		||||
        bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
			
		||||
 | 
			
		||||
        static inline std::string MakeChallenge() {
 | 
			
		||||
            char buf[16];
 | 
			
		||||
            std::sprintf(buf,"%06llu",MicroService::instance().Random(1,999999));
 | 
			
		||||
            return buf;
 | 
			
		||||
            return std::to_string(rand() % 999999);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static MFAServer *  instance_;
 | 
			
		||||
        MFAChallengeCache   Cache_;
 | 
			
		||||
        MFAServer() noexcept:
 | 
			
		||||
            SubSystemServer("MFServer", "MFA-SVR", "mfa")
 | 
			
		||||
@@ -62,7 +51,7 @@ namespace OpenWifi {
 | 
			
		||||
        void CleanCache();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline auto MFAServer() { return MFAServer::instance(); }
 | 
			
		||||
    inline MFAServer & MFAServer() { return *MFAServer::instance(); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWSEC_MFASERVER_H
 | 
			
		||||
 
 | 
			
		||||
@@ -2,13 +2,13 @@
 | 
			
		||||
// Created by stephane bourque on 2021-07-10.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_asset_server.h"
 | 
			
		||||
#include "RESTAPI_AssetServer.h"
 | 
			
		||||
#include "Poco/File.h"
 | 
			
		||||
#include "framework/RESTAPI_protocol.h"
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    void RESTAPI_asset_server::DoGet() {
 | 
			
		||||
    void RESTAPI_AssetServer::DoGet() {
 | 
			
		||||
        Poco::File  AssetFile;
 | 
			
		||||
 | 
			
		||||
        if(Request->getURI().find("/favicon.ico") != std::string::npos) {
 | 
			
		||||
@@ -2,14 +2,15 @@
 | 
			
		||||
// Created by stephane bourque on 2021-07-10.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef UCENTRALSEC_RESTAPI_ASSETSERVER_H
 | 
			
		||||
#define UCENTRALSEC_RESTAPI_ASSETSERVER_H
 | 
			
		||||
 | 
			
		||||
#include "../framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_asset_server : public RESTAPIHandler {
 | 
			
		||||
    class RESTAPI_AssetServer : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 std::vector<std::string>
 | 
			
		||||
                                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
@@ -18,7 +19,6 @@ namespace OpenWifi {
 | 
			
		||||
                                          Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
                                          Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                          Server,
 | 
			
		||||
                                          TransactionId,
 | 
			
		||||
                                          Internal, false) {}
 | 
			
		||||
        static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" ,
 | 
			
		||||
                                                                                         "/favicon.ico"}; };
 | 
			
		||||
@@ -32,3 +32,5 @@ namespace OpenWifi {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_RESTAPI_ASSETSERVER_H
 | 
			
		||||
@@ -11,61 +11,46 @@
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::DoGet() {
 | 
			
		||||
 | 
			
		||||
        auto Action = GetParameter("action","");
 | 
			
		||||
        auto Id = GetParameter("id","");
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::ActionLink Link;
 | 
			
		||||
        if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
 | 
			
		||||
            return DoReturnA404();
 | 
			
		||||
 | 
			
		||||
        if(Action=="password_reset")
 | 
			
		||||
            return RequestResetPassword(Link);
 | 
			
		||||
            return RequestResetPassword(Id);
 | 
			
		||||
        else if(Action=="email_verification")
 | 
			
		||||
            return DoEmailVerification(Link);
 | 
			
		||||
            return DoEmailVerification(Id);
 | 
			
		||||
        else
 | 
			
		||||
            return DoReturnA404();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::DoPost() {
 | 
			
		||||
        auto Action = GetParameter("action","");
 | 
			
		||||
        auto Id = GetParameter("id","");
 | 
			
		||||
 | 
			
		||||
        Logger_.information(Poco::format("COMPLETE-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
 | 
			
		||||
        if(Action=="password_reset")
 | 
			
		||||
            return CompleteResetPassword();
 | 
			
		||||
            CompleteResetPassword(Id);
 | 
			
		||||
        else
 | 
			
		||||
            return DoReturnA404();
 | 
			
		||||
            DoReturnA404();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
 | 
			
		||||
        Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId));
 | 
			
		||||
    void RESTAPI_action_links::RequestResetPassword(std::string &Id) {
 | 
			
		||||
        Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
 | 
			
		||||
        Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
 | 
			
		||||
        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
			
		||||
        Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                          {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
			
		||||
        SendHTMLFileBack(FormFile,FormVars);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::CompleteResetPassword() {
 | 
			
		||||
    void RESTAPI_action_links::CompleteResetPassword(std::string &Id) {
 | 
			
		||||
        //  form has been posted...
 | 
			
		||||
        RESTAPI_PartHandler PartHandler;
 | 
			
		||||
        Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
			
		||||
        if (!Form.empty()) {
 | 
			
		||||
 | 
			
		||||
            auto Password1 = Form.get("password1","bla");
 | 
			
		||||
            auto Password2 = Form.get("password1","blu");
 | 
			
		||||
            auto Id = Form.get("id","");
 | 
			
		||||
            auto Now = std::time(nullptr);
 | 
			
		||||
 | 
			
		||||
            SecurityObjects::ActionLink Link;
 | 
			
		||||
            if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
 | 
			
		||||
                return DoReturnA404();
 | 
			
		||||
 | 
			
		||||
            if(Now > Link.expires) {
 | 
			
		||||
                StorageService()->ActionLinksDB().CancelAction(Id);
 | 
			
		||||
                return DoReturnA404();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Id = Form.get("id","");
 | 
			
		||||
            if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
@@ -77,9 +62,7 @@ namespace OpenWifi {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SecurityObjects::UserInfo   UInfo;
 | 
			
		||||
 | 
			
		||||
            bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
			
		||||
            if(!Found) {
 | 
			
		||||
            if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
			
		||||
@@ -93,63 +76,43 @@ namespace OpenWifi {
 | 
			
		||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo);
 | 
			
		||||
            if(!GoodPassword) {
 | 
			
		||||
            if(!AuthService()->SetPassword(Password1,UInfo)) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
			
		||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
            StorageService()->UpdateUserInfo(UInfo.email,Id,UInfo);
 | 
			
		||||
            Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
 | 
			
		||||
            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                              {"USERNAME", UInfo.email},
 | 
			
		||||
                                              {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
			
		||||
            StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
			
		||||
            SendHTMLFileBack(FormFile,FormVars);
 | 
			
		||||
        } else {
 | 
			
		||||
            DoReturnA404();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
 | 
			
		||||
        auto Now = std::time(nullptr);
 | 
			
		||||
 | 
			
		||||
        if(Now > Link.expires) {
 | 
			
		||||
            StorageService()->ActionLinksDB().CancelAction(Link.id);
 | 
			
		||||
            return DoReturnA404();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::DoEmailVerification(std::string &Id) {
 | 
			
		||||
        SecurityObjects::UserInfo UInfo;
 | 
			
		||||
        bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
			
		||||
        if (!Found) {
 | 
			
		||||
            Types::StringPairVec FormVars{{"UUID",       Link.id},
 | 
			
		||||
 | 
			
		||||
        Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), Id));
 | 
			
		||||
        if (!StorageService()->GetUserById(Id, UInfo)) {
 | 
			
		||||
            Types::StringPairVec FormVars{{"UUID",       Id},
 | 
			
		||||
                                          {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
 | 
			
		||||
            Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
 | 
			
		||||
            return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email));
 | 
			
		||||
        UInfo.waitingForEmailCheck = false;
 | 
			
		||||
        UInfo.validated = true;
 | 
			
		||||
        UInfo.lastEmailCheck = std::time(nullptr);
 | 
			
		||||
        UInfo.validationDate = std::time(nullptr);
 | 
			
		||||
        UInfo.modified  = std::time(nullptr);
 | 
			
		||||
        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},
 | 
			
		||||
        StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo);
 | 
			
		||||
        Types::StringPairVec FormVars{{"UUID",     Id},
 | 
			
		||||
                                      {"USERNAME", UInfo.email},
 | 
			
		||||
                                      {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
			
		||||
        Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
 | 
			
		||||
        StorageService()->ActionLinksDB().CompleteAction(Link.id);
 | 
			
		||||
        SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,28 +2,28 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_action_links : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
             std::vector<std::string>{
 | 
			
		||||
                                        Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
                                        Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
                                        Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                        Server,
 | 
			
		||||
                                        TransactionId,
 | 
			
		||||
                                        Internal,
 | 
			
		||||
                                        false,
 | 
			
		||||
                                        true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
			
		||||
                                        false) {}
 | 
			
		||||
        static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
 | 
			
		||||
        void RequestResetPassword(SecurityObjects::ActionLink &Link);
 | 
			
		||||
        void CompleteResetPassword();
 | 
			
		||||
        void DoEmailVerification(SecurityObjects::ActionLink &Link);
 | 
			
		||||
        void RequestResetPassword(std::string &Id);
 | 
			
		||||
        void CompleteResetPassword(std::string &Id);
 | 
			
		||||
        void DoEmailVerification(std::string &Id);
 | 
			
		||||
        void DoReturnA404();
 | 
			
		||||
 | 
			
		||||
        void DoGet() final;
 | 
			
		||||
@@ -32,3 +32,5 @@ namespace OpenWifi {
 | 
			
		||||
        void DoPut() final {};
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_RESTAPI_ACTION_LINKS_H
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_avatar_handler.h"
 | 
			
		||||
#include "RESTAPI_avatarHandler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "Poco/Net/HTMLForm.h"
 | 
			
		||||
#include "framework/RESTAPI_protocol.h"
 | 
			
		||||
@@ -22,26 +22,33 @@ namespace OpenWifi {
 | 
			
		||||
            Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
			
		||||
        }
 | 
			
		||||
        Poco::CountingInputStream InputStream(Stream);
 | 
			
		||||
        Poco::StreamCopier::copyStream(InputStream, OutputStream_);
 | 
			
		||||
        Length_ = OutputStream_.str().size();
 | 
			
		||||
        std::ofstream OutputStream(TempFile_.path(), std::ofstream::out);
 | 
			
		||||
        Poco::StreamCopier::copyStream(InputStream, OutputStream);
 | 
			
		||||
        Length_ = InputStream.chars();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_avatar_handler::DoPost() {
 | 
			
		||||
        std::string Id = UserInfo_.userinfo.id;
 | 
			
		||||
    void RESTAPI_avatarHandler::DoPost() {
 | 
			
		||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
			
		||||
        SecurityObjects::UserInfo UInfo;
 | 
			
		||||
 | 
			
		||||
        std::stringstream SS;
 | 
			
		||||
        AvatarPartHandler partHandler(Id, Logger_, SS);
 | 
			
		||||
        if (Id.empty() || !StorageService()->GetUserById(Id, UInfo)) {
 | 
			
		||||
            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::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()->AvatarDB().SetAvatar(UserInfo_.userinfo.email,
 | 
			
		||||
                                 Id, SS.str(), partHandler.ContentType(), partHandler.Name());
 | 
			
		||||
            StorageService()->UserDB().SetAvatar(Id,"1");
 | 
			
		||||
            StorageService()->SetAvatar(UserInfo_.userinfo.email,
 | 
			
		||||
                                 Id, TmpFile, partHandler.ContentType(), partHandler.Name());
 | 
			
		||||
        } else {
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
 | 
			
		||||
@@ -50,31 +57,27 @@ namespace OpenWifi {
 | 
			
		||||
        ReturnObject(Answer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_avatar_handler::DoGet() {
 | 
			
		||||
    void RESTAPI_avatarHandler::DoGet() {
 | 
			
		||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
			
		||||
        if (Id.empty()) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string Type, Name, AvatarContent;
 | 
			
		||||
        if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
 | 
			
		||||
        Poco::TemporaryFile TempAvatar;
 | 
			
		||||
        std::string Type, Name;
 | 
			
		||||
        if (!StorageService()->GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) {
 | 
			
		||||
            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, "");
 | 
			
		||||
 | 
			
		||||
        if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
 | 
			
		||||
            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
			
		||||
        if (Id.empty()) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
        if (!StorageService()->DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StorageService()->UserDB().SetAvatar(Id,"");
 | 
			
		||||
        OK();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-07-15.
 | 
			
		||||
//
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifndef UCENTRALSEC_RESTAPI_AVATARHANDLER_H
 | 
			
		||||
#define UCENTRALSEC_RESTAPI_AVATARHANDLER_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
@@ -9,28 +12,28 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    class AvatarPartHandler : public Poco::Net::PartHandler {
 | 
			
		||||
    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)),
 | 
			
		||||
                Logger_(Logger),
 | 
			
		||||
                OutputStream_(ofs){
 | 
			
		||||
                TempFile_(TmpFile){
 | 
			
		||||
        }
 | 
			
		||||
        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_; }
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] std::string FileName() const { return TempFile_.path(); }
 | 
			
		||||
    private:
 | 
			
		||||
        uint64_t        Length_ = 0;
 | 
			
		||||
        std::string     FileType_;
 | 
			
		||||
        std::string     Name_;
 | 
			
		||||
        std::string     Id_;
 | 
			
		||||
        Poco::Logger    &Logger_;
 | 
			
		||||
        std::stringstream &OutputStream_;
 | 
			
		||||
        Poco::TemporaryFile &TempFile_;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class RESTAPI_avatar_handler : public RESTAPIHandler {
 | 
			
		||||
    class RESTAPI_avatarHandler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 std::vector<std::string>{
 | 
			
		||||
                                         Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
@@ -38,7 +41,6 @@ namespace OpenWifi {
 | 
			
		||||
                                         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/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.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef OWSEC_RESTAPI_EMAIL_HANDLER_H
 | 
			
		||||
#define OWSEC_RESTAPI_EMAIL_HANDLER_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_email_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal) {}
 | 
			
		||||
        static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};}
 | 
			
		||||
        void DoGet() final {};
 | 
			
		||||
@@ -23,3 +24,5 @@ namespace OpenWifi {
 | 
			
		||||
        void DoPut() final {};
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWSEC_RESTAPI_EMAIL_HANDLER_H
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										125
									
								
								src/RESTAPI/RESTAPI_oauth2Handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/RESTAPI/RESTAPI_oauth2Handler.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
//
 | 
			
		||||
//	License type: BSD 3-Clause License
 | 
			
		||||
//	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | 
			
		||||
//
 | 
			
		||||
//	Created by Stephane Bourque on 2021-03-04.
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "Poco/JSON/Parser.h"
 | 
			
		||||
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "RESTAPI_oauth2Handler.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "framework/RESTAPI_protocol.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	void RESTAPI_oauth2Handler::DoGet() {
 | 
			
		||||
        if (!IsAuthorized()) {
 | 
			
		||||
            return UnAuthorized("Not authorized.");
 | 
			
		||||
        }
 | 
			
		||||
        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;
 | 
			
		||||
            UserInfo_.userinfo.to_json(Me);
 | 
			
		||||
            return ReturnObject(Me);
 | 
			
		||||
        }
 | 
			
		||||
        BadRequest("Ill-formed request. Please consult documentation.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_oauth2Handler::DoDelete() {
 | 
			
		||||
        if (!IsAuthorized()) {
 | 
			
		||||
            return UnAuthorized("Not authorized.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
 | 
			
		||||
        if (Token == SessionToken_) {
 | 
			
		||||
            AuthService()->Logout(Token);
 | 
			
		||||
            return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
 | 
			
		||||
        NotFound();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_oauth2Handler::DoPost() {
 | 
			
		||||
        auto Obj = ParseStream();
 | 
			
		||||
        auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
			
		||||
        auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
			
		||||
        auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
			
		||||
 | 
			
		||||
        Poco::toLowerInPlace(userId);
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) {
 | 
			
		||||
            Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString()));
 | 
			
		||||
            Poco::JSON::Object  Answer;
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::ACCESSPOLICY, Daemon()->GetAccessPolicy());
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, Daemon()->GetPasswordPolicy());
 | 
			
		||||
            return ReturnObject(Answer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
 | 
			
		||||
            //  Send an email to the userId
 | 
			
		||||
            Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
			
		||||
            SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
            if(AuthService::SendEmailToUser(userId,AuthService::FORGOT_PASSWORD))
 | 
			
		||||
                Logger_.information(Poco::format("Send password reset link to %s",userId));
 | 
			
		||||
            UInfo.webtoken.userMustChangePassword=true;
 | 
			
		||||
            Poco::JSON::Object ReturnObj;
 | 
			
		||||
            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("Unrecognized credentials (username/password).");
 | 
			
		||||
            }
 | 
			
		||||
            return UnAuthorized("Unrecognized credentials (username/password).");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
 | 
			
		||||
            Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
			
		||||
            if(Obj->has("uuid")) {
 | 
			
		||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
                if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
 | 
			
		||||
                    Poco::JSON::Object ReturnObj;
 | 
			
		||||
                    UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
                    return ReturnObject(ReturnObj);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return UnAuthorized("Unrecognized credentials (username/password).");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
        auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
 | 
			
		||||
        if (Code==AuthService::SUCCESS) {
 | 
			
		||||
            Poco::JSON::Object ReturnObj;
 | 
			
		||||
            if(AuthService()->RequiresMFA(UInfo)) {
 | 
			
		||||
                if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
 | 
			
		||||
                    return ReturnObject(ReturnObj);
 | 
			
		||||
                }
 | 
			
		||||
                Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
            }
 | 
			
		||||
            UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
            return ReturnObject(ReturnObj);
 | 
			
		||||
        } else {
 | 
			
		||||
            switch(Code) {
 | 
			
		||||
                case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break;
 | 
			
		||||
                case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break;
 | 
			
		||||
                case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break;
 | 
			
		||||
                case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break;
 | 
			
		||||
                case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break;
 | 
			
		||||
                default: return UnAuthorized("Unrecognized credentials (username/password)."); break;
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -6,21 +6,22 @@
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef UCENTRAL_RESTAPI_OAUTH2HANDLER_H
 | 
			
		||||
#define UCENTRAL_RESTAPI_OAUTH2HANDLER_H
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_oauth2_handler : public RESTAPIHandler {
 | 
			
		||||
	class RESTAPI_oauth2Handler : public RESTAPIHandler {
 | 
			
		||||
	  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,
 | 
			
		||||
							 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, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
			
		||||
													  Internal, false) {}
 | 
			
		||||
		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
@@ -28,5 +29,4 @@ namespace OpenWifi {
 | 
			
		||||
		void DoPut() final {};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
 | 
			
		||||
@@ -1,159 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//	License type: BSD 3-Clause License
 | 
			
		||||
//	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | 
			
		||||
//
 | 
			
		||||
//	Created by Stephane Bourque on 2021-03-04.
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "Poco/JSON/Parser.h"
 | 
			
		||||
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "RESTAPI_oauth2_handler.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "framework/RESTAPI_protocol.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTAPI_db_helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_oauth2_handler::DoGet() {
 | 
			
		||||
	    bool Expired = false, Contacted = false;
 | 
			
		||||
        if (!IsAuthorized(Expired, Contacted)) {
 | 
			
		||||
            if(Expired)
 | 
			
		||||
                return UnAuthorized(RESTAPI::Errors::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_oauth2_handler::DoDelete() {
 | 
			
		||||
	    bool Expired = false, Contacted=false;
 | 
			
		||||
	    if (!IsAuthorized(Expired, Contacted)) {
 | 
			
		||||
	        if(Expired)
 | 
			
		||||
	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
 | 
			
		||||
	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation, INVALID_TOKEN);
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
        auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
 | 
			
		||||
        if (Token == SessionToken_) {
 | 
			
		||||
            AuthService()->Logout(Token);
 | 
			
		||||
            return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
 | 
			
		||||
        NotFound();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_oauth2_handler::DoPost() {
 | 
			
		||||
        auto Obj = ParseStream();
 | 
			
		||||
        auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
			
		||||
        auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
			
		||||
        auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
			
		||||
 | 
			
		||||
        Poco::toLowerInPlace(userId);
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) {
 | 
			
		||||
            Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString()));
 | 
			
		||||
            Poco::JSON::Object  Answer;
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
 | 
			
		||||
            return ReturnObject(Answer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
 | 
			
		||||
            SecurityObjects::UserInfo UInfo1;
 | 
			
		||||
            auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1);
 | 
			
		||||
            if(UserExists) {
 | 
			
		||||
                Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
			
		||||
                SecurityObjects::ActionLink NewLink;
 | 
			
		||||
 | 
			
		||||
                NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
 | 
			
		||||
                NewLink.id = MicroService::CreateUUID();
 | 
			
		||||
                NewLink.userId = UInfo1.id;
 | 
			
		||||
                NewLink.created = std::time(nullptr);
 | 
			
		||||
                NewLink.expires = NewLink.created + (24*60*60);
 | 
			
		||||
                NewLink.userAction = true;
 | 
			
		||||
                StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
			
		||||
 | 
			
		||||
                Poco::JSON::Object ReturnObj;
 | 
			
		||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
			
		||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
                return ReturnObject(ReturnObj);
 | 
			
		||||
            } else {
 | 
			
		||||
                Poco::JSON::Object ReturnObj;
 | 
			
		||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
			
		||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
                return ReturnObject(ReturnObj);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,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")) {
 | 
			
		||||
                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()->Authorize(userId, password, newPassword, UInfo, Expired);
 | 
			
		||||
        if (Code==SUCCESS) {
 | 
			
		||||
            Poco::JSON::Object ReturnObj;
 | 
			
		||||
            if(AuthService()->RequiresMFA(UInfo)) {
 | 
			
		||||
                if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
			
		||||
                    return ReturnObject(ReturnObj);
 | 
			
		||||
                }
 | 
			
		||||
                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
            }
 | 
			
		||||
            UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
            return ReturnObject(ReturnObj);
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            switch(Code) {
 | 
			
		||||
                case INVALID_CREDENTIALS:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code);
 | 
			
		||||
                case PASSWORD_INVALID:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code);
 | 
			
		||||
                case PASSWORD_ALREADY_USED:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code);
 | 
			
		||||
                case USERNAME_PENDING_VERIFICATION:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code);
 | 
			
		||||
                case PASSWORD_CHANGE_REQUIRED:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code);
 | 
			
		||||
                default:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break;
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -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)) {
 | 
			
		||||
                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;
 | 
			
		||||
@@ -30,13 +30,7 @@ namespace OpenWifi {
 | 
			
		||||
            if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
 | 
			
		||||
                return OK();
 | 
			
		||||
            }
 | 
			
		||||
            return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT &&
 | 
			
		||||
            UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER &&
 | 
			
		||||
            UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
 | 
			
		||||
            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights,ACCESS_DENIED);
 | 
			
		||||
            return BadRequest("Code and number could not be validated");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Obj->has("to") &&
 | 
			
		||||
@@ -47,7 +41,7 @@ namespace OpenWifi {
 | 
			
		||||
            if(SMSSender()->Send(PhoneNumber, Text))
 | 
			
		||||
                return OK();
 | 
			
		||||
 | 
			
		||||
            return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
 | 
			
		||||
            return InternalError("SMS Message could not be sent.");
 | 
			
		||||
        }
 | 
			
		||||
        BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,20 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_sms_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal) {}
 | 
			
		||||
                                                  static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};}
 | 
			
		||||
        void DoGet() final {};
 | 
			
		||||
@@ -23,3 +24,5 @@ namespace OpenWifi {
 | 
			
		||||
        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.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_system_endpoints_handler.h"
 | 
			
		||||
#include "RESTAPI_systemEndpoints_handler.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_system_endpoints_handler::DoGet() {
 | 
			
		||||
    void RESTAPI_systemEndpoints_handler::DoGet() {
 | 
			
		||||
        auto Services = MicroService::instance().GetServices();
 | 
			
		||||
        SecurityObjects::SystemEndpointList L;
 | 
			
		||||
        for(const auto &i:Services) {
 | 
			
		||||
@@ -2,19 +2,19 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_system_endpoints_handler : public RESTAPIHandler {
 | 
			
		||||
    class RESTAPI_systemEndpoints_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 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/systemEndpoints"}; };
 | 
			
		||||
        void DoGet() final;
 | 
			
		||||
@@ -23,3 +23,5 @@ namespace OpenWifi {
 | 
			
		||||
        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,11 @@
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_user_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "Poco/JSON/Parser.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_user_handler::DoGet() {
 | 
			
		||||
        std::string Id = GetBinding("id", "");
 | 
			
		||||
        if(Id.empty()) {
 | 
			
		||||
@@ -24,19 +19,13 @@ namespace OpenWifi {
 | 
			
		||||
        std::string Arg;
 | 
			
		||||
        SecurityObjects::UserInfo   UInfo;
 | 
			
		||||
        if(HasParameter("byEmail",Arg) && Arg=="true") {
 | 
			
		||||
            if(!StorageService()->UserDB().GetUserByEmail(Id,UInfo)) {
 | 
			
		||||
            if(!StorageService()->GetUserByEmail(Id,UInfo)) {
 | 
			
		||||
                return NotFound();
 | 
			
		||||
            }
 | 
			
		||||
        } else if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
 | 
			
		||||
        } else if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) {
 | 
			
		||||
            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Poco::JSON::Object  UserInfoObject;
 | 
			
		||||
        Sanitize(UserInfo_, UInfo);
 | 
			
		||||
        UInfo.to_json(UserInfoObject);
 | 
			
		||||
        ReturnObject(UserInfoObject);
 | 
			
		||||
    }
 | 
			
		||||
@@ -48,22 +37,18 @@ namespace OpenWifi {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::UserInfo UInfo;
 | 
			
		||||
        if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
 | 
			
		||||
        if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
 | 
			
		||||
            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
 | 
			
		||||
        if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AuthService()->DeleteUserFromCache(Id);
 | 
			
		||||
        StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id);
 | 
			
		||||
        StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id);
 | 
			
		||||
        StorageService()->UserTokenDB().RevokeAllTokens(Id);
 | 
			
		||||
        if(AuthService()->DeleteUserFromCache(UInfo.email))
 | 
			
		||||
            ;
 | 
			
		||||
        Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
 | 
			
		||||
        StorageService()->RevokeAllTokens(UInfo.email);
 | 
			
		||||
        Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
 | 
			
		||||
        OK();
 | 
			
		||||
    }
 | 
			
		||||
@@ -74,63 +59,49 @@ namespace OpenWifi {
 | 
			
		||||
            return BadRequest(RESTAPI::Errors::IdMustBe0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::UserInfo   NewUser;
 | 
			
		||||
        RESTAPI_utils::from_request(NewUser,*Request);
 | 
			
		||||
        if(NewUser.userRole == SecurityObjects::UNKNOWN) {
 | 
			
		||||
        SecurityObjects::UserInfo   UInfo;
 | 
			
		||||
        RESTAPI_utils::from_request(UInfo,*Request);
 | 
			
		||||
 | 
			
		||||
        if(UInfo.userRole == SecurityObjects::UNKNOWN) {
 | 
			
		||||
            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)) {
 | 
			
		||||
            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Poco::toLowerInPlace(NewUser.email);
 | 
			
		||||
        if(!Utils::ValidEMailAddress(NewUser.email)) {
 | 
			
		||||
        Poco::toLowerInPlace(UInfo.email);
 | 
			
		||||
        if(!Utils::ValidEMailAddress(UInfo.email)) {
 | 
			
		||||
            return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!NewUser.currentPassword.empty()) {
 | 
			
		||||
            if(!AuthService()->ValidatePassword(NewUser.currentPassword)) {
 | 
			
		||||
        if(!UInfo.currentPassword.empty()) {
 | 
			
		||||
            if(!AuthService()->ValidatePassword(UInfo.currentPassword)) {
 | 
			
		||||
                return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(NewUser.name.empty())
 | 
			
		||||
            NewUser.name = NewUser.email;
 | 
			
		||||
        if(UInfo.name.empty())
 | 
			
		||||
            UInfo.name = UInfo.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()->UserDB().CreateUser(NewUser.email,NewUser)) {
 | 
			
		||||
            Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email));
 | 
			
		||||
        if(!StorageService()->CreateUser(UInfo.email,UInfo)) {
 | 
			
		||||
            Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email));
 | 
			
		||||
            return BadRequest(RESTAPI::Errors::RecordNotCreated);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(GetParameter("email_verification","false")=="true") {
 | 
			
		||||
            if(AuthService::VerifyEmail(NewUser))
 | 
			
		||||
                Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email));
 | 
			
		||||
            StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
 | 
			
		||||
            if(AuthService::VerifyEmail(UInfo))
 | 
			
		||||
                Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email));
 | 
			
		||||
            StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) {
 | 
			
		||||
            Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email));
 | 
			
		||||
        if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) {
 | 
			
		||||
            Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email));
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Poco::JSON::Object  UserInfoObject;
 | 
			
		||||
        Sanitize(UserInfo_, NewUser);
 | 
			
		||||
        NewUser.to_json(UserInfoObject);
 | 
			
		||||
        UInfo.to_json(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')",UInfo.email, UserInfo_.userinfo.email));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_user_handler::DoPut() {
 | 
			
		||||
@@ -140,14 +111,10 @@ namespace OpenWifi {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::UserInfo   Existing;
 | 
			
		||||
        if(!StorageService()->UserDB().GetUserById(Id,Existing)) {
 | 
			
		||||
        if(!StorageService()->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)) {
 | 
			
		||||
@@ -159,34 +126,18 @@ namespace OpenWifi {
 | 
			
		||||
            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,
 | 
			
		||||
        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("userRole"))
 | 
			
		||||
            Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
			
		||||
        if(RawObject->has("notes")) {
 | 
			
		||||
            SecurityObjects::NoteInfoVec NIV;
 | 
			
		||||
            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
 | 
			
		||||
@@ -210,56 +161,33 @@ namespace OpenWifi {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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")) {
 | 
			
		||||
            if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") {
 | 
			
		||||
                Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
 | 
			
		||||
                auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
 | 
			
		||||
                auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
 | 
			
		||||
                if(Info->isArray("mobiles")) {
 | 
			
		||||
                    Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
 | 
			
		||||
                }
 | 
			
		||||
                    if (NewUser.userTypeProprietaryInfo.mobiles.empty() ||
 | 
			
		||||
                        !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,
 | 
			
		||||
                                                    UserInfo_.userinfo.email)) {
 | 
			
		||||
                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);
 | 
			
		||||
                if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
 | 
			
		||||
                    return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
			
		||||
                }
 | 
			
		||||
                } 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 if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
 | 
			
		||||
                Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
 | 
			
		||||
            } else {
 | 
			
		||||
                Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
			
		||||
                Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
			
		||||
                Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
			
		||||
                if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
 | 
			
		||||
                    return BadRequest(RESTAPI::Errors::BadMFAMethod);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
 | 
			
		||||
        if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
 | 
			
		||||
            SecurityObjects::UserInfo   NewUserInfo;
 | 
			
		||||
            StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
 | 
			
		||||
            StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
 | 
			
		||||
            Poco::JSON::Object  ModifiedObject;
 | 
			
		||||
            Sanitize(UserInfo_, NewUserInfo);
 | 
			
		||||
            NewUserInfo.to_json(ModifiedObject);
 | 
			
		||||
            return ReturnObject(ModifiedObject);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,15 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_user_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 std::vector<std::string>
 | 
			
		||||
                                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
@@ -18,7 +19,6 @@ namespace OpenWifi {
 | 
			
		||||
                                          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/user/{id}"}; };
 | 
			
		||||
        void DoGet() final;
 | 
			
		||||
@@ -29,3 +29,6 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_RESTAPI_USER_HANDLER_H
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/RESTAPI_protocol.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    void RESTAPI_users_handler::DoGet() {
 | 
			
		||||
@@ -16,13 +15,12 @@ namespace OpenWifi {
 | 
			
		||||
        if(QB_.Select.empty()) {
 | 
			
		||||
            Poco::JSON::Array ArrayObj;
 | 
			
		||||
            Poco::JSON::Object Answer;
 | 
			
		||||
            if (StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users)) {
 | 
			
		||||
                for (auto &i : Users) {
 | 
			
		||||
            if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
 | 
			
		||||
                for (const auto &i : Users) {
 | 
			
		||||
                    Poco::JSON::Object Obj;
 | 
			
		||||
                    if (IdOnly) {
 | 
			
		||||
                        ArrayObj.add(i.id);
 | 
			
		||||
                        ArrayObj.add(i.Id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Sanitize(UserInfo_, i);
 | 
			
		||||
                        i.to_json(Obj);
 | 
			
		||||
                        ArrayObj.add(Obj);
 | 
			
		||||
                    }
 | 
			
		||||
@@ -31,16 +29,15 @@ namespace OpenWifi {
 | 
			
		||||
            }
 | 
			
		||||
            return ReturnObject(Answer);
 | 
			
		||||
        } else {
 | 
			
		||||
            Types::StringVec IDs = Utils::Split(QB_.Select);
 | 
			
		||||
            Poco::JSON::Array ArrayObj;
 | 
			
		||||
            for(auto &i:SelectedRecords()) {
 | 
			
		||||
            for(auto &i:IDs) {
 | 
			
		||||
                SecurityObjects::UserInfo   UInfo;
 | 
			
		||||
                auto tI{i};
 | 
			
		||||
                if(StorageService()->UserDB().GetUserById(i,UInfo)) {
 | 
			
		||||
                if(StorageService()->GetUserById(i,UInfo)) {
 | 
			
		||||
                    Poco::JSON::Object Obj;
 | 
			
		||||
                    if (IdOnly) {
 | 
			
		||||
                        ArrayObj.add(UInfo.id);
 | 
			
		||||
                        ArrayObj.add(UInfo.Id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Sanitize(UserInfo_, UInfo);
 | 
			
		||||
                        UInfo.to_json(Obj);
 | 
			
		||||
                        ArrayObj.add(Obj);
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,20 +2,20 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_users_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 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/users"}; };
 | 
			
		||||
        void DoGet() final;
 | 
			
		||||
@@ -25,3 +25,5 @@ namespace OpenWifi {
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_RESTAPI_USERS_HANDLER_H
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,18 @@
 | 
			
		||||
// Created by stephane bourque on 2021-07-01.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_validate_token_handler.h"
 | 
			
		||||
#include "RESTAPI_validateToken_handler.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    void RESTAPI_validate_token_handler::DoGet() {
 | 
			
		||||
    void RESTAPI_validateToken_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()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) {
 | 
			
		||||
                if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo)) {
 | 
			
		||||
                    Poco::JSON::Object Obj;
 | 
			
		||||
                    SecObj.to_json(Obj);
 | 
			
		||||
                    return ReturnObject(Obj);
 | 
			
		||||
@@ -2,20 +2,20 @@
 | 
			
		||||
// 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"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class RESTAPI_validate_token_handler : public RESTAPIHandler {
 | 
			
		||||
    class RESTAPI_validateToken_handler : public RESTAPIHandler {
 | 
			
		||||
    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,
 | 
			
		||||
                                 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/validateToken"}; };
 | 
			
		||||
        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     uploader;
 | 
			
		||||
        std::string     digest;
 | 
			
		||||
        bool            latest=0;
 | 
			
		||||
        bool            latest=false;
 | 
			
		||||
        SecurityObjects::NoteInfoVec    notes;
 | 
			
		||||
        uint64_t        created=0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
#ifdef	TIP_GATEWAY_SERVICE
 | 
			
		||||
#include "DeviceRegistry.h"
 | 
			
		||||
#include "CapabilitiesCache.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_GWobjects.h"
 | 
			
		||||
@@ -27,7 +26,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
	void Device::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
		field_to_json(Obj,"serialNumber", SerialNumber);
 | 
			
		||||
#ifdef TIP_GATEWAY_SERVICE
 | 
			
		||||
		field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible));
 | 
			
		||||
		field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible));
 | 
			
		||||
#endif
 | 
			
		||||
		field_to_json(Obj,"macAddress", MACAddress);
 | 
			
		||||
		field_to_json(Obj,"manufacturer", Manufacturer);
 | 
			
		||||
@@ -69,7 +68,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool Device::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool Device::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"serialNumber",SerialNumber);
 | 
			
		||||
			field_from_json(Obj,"deviceType",DeviceType);
 | 
			
		||||
@@ -146,10 +145,9 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		field_to_json(Obj,"custom", Custom);
 | 
			
		||||
		field_to_json(Obj,"waitingForFile", WaitingForFile);
 | 
			
		||||
		field_to_json(Obj,"attachFile", AttachDate);
 | 
			
		||||
		field_to_json(Obj,"executionTime", executionTime);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"name",Name);
 | 
			
		||||
			field_from_json(Obj,"configuration",Configuration);
 | 
			
		||||
@@ -168,7 +166,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		field_to_json(Obj,"created", created);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"serialNumber",serialNumber);
 | 
			
		||||
			field_from_json(Obj,"author",author);
 | 
			
		||||
@@ -181,6 +179,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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,"txBytes", TX);
 | 
			
		||||
		field_to_json(Obj,"rxBytes", RX);
 | 
			
		||||
@@ -191,10 +190,6 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		field_to_json(Obj,"lastContact", LastContact);
 | 
			
		||||
		field_to_json(Obj,"associations_2G", Associations_2G);
 | 
			
		||||
		field_to_json(Obj,"associations_5G", Associations_5G);
 | 
			
		||||
		field_to_json(Obj,"webSocketClients", webSocketClients);
 | 
			
		||||
		field_to_json(Obj,"websocketPackets", websocketPackets);
 | 
			
		||||
		field_to_json(Obj,"kafkaClients", kafkaClients);
 | 
			
		||||
		field_to_json(Obj,"kafkaPackets", kafkaPackets);
 | 
			
		||||
 | 
			
		||||
		switch(VerifiedCertificate) {
 | 
			
		||||
			case NO_CERTIFICATE:
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,8 @@
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef UCENTRAL_RESTAPI_OBJECTS_H
 | 
			
		||||
#define UCENTRAL_RESTAPI_OBJECTS_H
 | 
			
		||||
 | 
			
		||||
#include "Poco/JSON/Object.h"
 | 
			
		||||
#include "RESTAPI_SecurityObjects.h"
 | 
			
		||||
@@ -22,6 +23,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
 | 
			
		||||
	struct ConnectionState {
 | 
			
		||||
		uint64_t MessageCount = 0 ;
 | 
			
		||||
		std::string SerialNumber;
 | 
			
		||||
		std::string Address;
 | 
			
		||||
		uint64_t UUID = 0 ;
 | 
			
		||||
		uint64_t PendingUUID = 0 ;
 | 
			
		||||
@@ -33,10 +35,6 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		std::string Firmware;
 | 
			
		||||
		CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
 | 
			
		||||
		std::string Compatible;
 | 
			
		||||
		uint64_t 	kafkaClients=0;
 | 
			
		||||
		uint64_t 	webSocketClients=0;
 | 
			
		||||
		uint64_t 	kafkaPackets=0;
 | 
			
		||||
		uint64_t 	websocketPackets=0;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -52,40 +50,40 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		std::string Firmware;
 | 
			
		||||
		std::string Compatible;
 | 
			
		||||
		std::string FWUpdatePolicy;
 | 
			
		||||
		uint64_t UUID = 0 ;
 | 
			
		||||
		uint64_t CreationTimestamp = 0 ;
 | 
			
		||||
		uint64_t LastConfigurationChange = 0 ;
 | 
			
		||||
		uint64_t LastConfigurationDownload = 0 ;
 | 
			
		||||
		uint64_t LastFWUpdate = 0 ;
 | 
			
		||||
		uint64_t UUID;
 | 
			
		||||
		uint64_t CreationTimestamp;
 | 
			
		||||
		uint64_t LastConfigurationChange;
 | 
			
		||||
		uint64_t LastConfigurationDownload;
 | 
			
		||||
		uint64_t LastFWUpdate;
 | 
			
		||||
		std::string Venue;
 | 
			
		||||
		std::string DevicePassword;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
		void to_json_with_status(Poco::JSON::Object &Obj) const;
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
		void Print() const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct Statistics {
 | 
			
		||||
		std::string SerialNumber;
 | 
			
		||||
		uint64_t 	UUID = 0 ;
 | 
			
		||||
		uint64_t 	UUID;
 | 
			
		||||
		std::string Data;
 | 
			
		||||
		uint64_t 	Recorded = 0;
 | 
			
		||||
		uint64_t 	Recorded;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct HealthCheck {
 | 
			
		||||
		std::string SerialNumber;
 | 
			
		||||
		uint64_t 	UUID = 0 ;
 | 
			
		||||
		uint64_t 	UUID;
 | 
			
		||||
		std::string Data;
 | 
			
		||||
		uint64_t 	Recorded = 0 ;
 | 
			
		||||
		uint64_t 	Sanity = 0 ;
 | 
			
		||||
		uint64_t 	Recorded;
 | 
			
		||||
		uint64_t 	Sanity;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct Capabilities {
 | 
			
		||||
		std::string Capabilities;
 | 
			
		||||
		uint64_t 	FirstUpdate = 0 ;
 | 
			
		||||
		uint64_t 	LastUpdate = 0 ;
 | 
			
		||||
		uint64_t 	FirstUpdate;
 | 
			
		||||
		uint64_t 	LastUpdate;
 | 
			
		||||
		void 		to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -103,22 +101,22 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		std::string SerialNumber;
 | 
			
		||||
		std::string Log;
 | 
			
		||||
		std::string Data;
 | 
			
		||||
		uint64_t 	Severity = 0 ;
 | 
			
		||||
		uint64_t 	Recorded = 0 ;
 | 
			
		||||
		uint64_t 	LogType = 0 ;
 | 
			
		||||
		uint64_t 	UUID = 0 ;
 | 
			
		||||
		uint64_t 	Severity;
 | 
			
		||||
		uint64_t 	Recorded;
 | 
			
		||||
		uint64_t 	LogType;
 | 
			
		||||
		uint64_t 	UUID;
 | 
			
		||||
		void 		to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct DefaultConfiguration {
 | 
			
		||||
		std::string Name;
 | 
			
		||||
		std::string Configuration;
 | 
			
		||||
		Types::StringVec Models;
 | 
			
		||||
		std::string Models;
 | 
			
		||||
		std::string Description;
 | 
			
		||||
		uint64_t 	Created;
 | 
			
		||||
		uint64_t 	LastModified;
 | 
			
		||||
		void 		to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
		bool 		from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool 		from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct CommandDetails {
 | 
			
		||||
@@ -140,7 +138,6 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		uint64_t AttachDate = 0 ;
 | 
			
		||||
		uint64_t AttachSize = 0 ;
 | 
			
		||||
		std::string AttachType;
 | 
			
		||||
		double 		executionTime = 0.0;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -150,26 +147,26 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		std::string author;
 | 
			
		||||
		uint64_t created;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct RttySessionDetails {
 | 
			
		||||
		std::string SerialNumber;
 | 
			
		||||
		std::string Server;
 | 
			
		||||
		uint64_t 	Port = 0 ;
 | 
			
		||||
		uint64_t 	Port;
 | 
			
		||||
		std::string Token;
 | 
			
		||||
		uint64_t 	TimeOut = 0 ;
 | 
			
		||||
		uint64_t 	TimeOut;
 | 
			
		||||
		std::string ConnectionId;
 | 
			
		||||
		uint64_t 	Started = 0 ;
 | 
			
		||||
		uint64_t 	Started;
 | 
			
		||||
		std::string CommandUUID;
 | 
			
		||||
		uint64_t 	ViewPort = 0 ;
 | 
			
		||||
		uint64_t 	ViewPort;
 | 
			
		||||
		std::string DevicePassword;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct Dashboard {
 | 
			
		||||
		uint64_t 		  snapshot = 0 ;
 | 
			
		||||
		uint64_t 		  numberOfDevices = 0 ;
 | 
			
		||||
		uint64_t 		  snapshot;
 | 
			
		||||
		uint64_t 		  numberOfDevices;
 | 
			
		||||
		Types::CountedMap commands;
 | 
			
		||||
		Types::CountedMap upTimes;
 | 
			
		||||
		Types::CountedMap memoryUsed;
 | 
			
		||||
@@ -194,3 +191,5 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRAL_RESTAPI_OBJECTS_H
 | 
			
		||||
 
 | 
			
		||||
@@ -10,30 +10,27 @@
 | 
			
		||||
#include "RESTAPI_ProvObjects.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
using OpenWifi::RESTAPI_utils::field_to_json;
 | 
			
		||||
using OpenWifi::RESTAPI_utils::field_from_json;
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj,"id",id);
 | 
			
		||||
        field_to_json(Obj,"name",name);
 | 
			
		||||
        field_to_json(Obj,"description",description);
 | 
			
		||||
        field_to_json(Obj,"created",created);
 | 
			
		||||
        field_to_json(Obj,"modified",modified);
 | 
			
		||||
        field_to_json(Obj,"notes",notes);
 | 
			
		||||
        field_to_json(Obj,"tags",tags);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"id",id);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"name",name);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"description",description);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"created",created);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"modified",modified);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"notes",notes);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj,"tags",tags);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json(Obj,"id",id);
 | 
			
		||||
            field_from_json(Obj,"name",name);
 | 
			
		||||
            field_from_json(Obj,"description",description);
 | 
			
		||||
            field_from_json(Obj,"created",created);
 | 
			
		||||
            field_from_json(Obj,"modified",modified);
 | 
			
		||||
            field_from_json(Obj,"notes",notes);
 | 
			
		||||
            field_from_json(Obj,"tags",tags);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"id",id);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"name",name);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"description",description);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"created",created);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"modified",modified);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"notes",notes);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj,"tags",tags);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -42,18 +39,18 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json( Obj,"users",users);
 | 
			
		||||
        field_to_json( Obj,"resources",resources);
 | 
			
		||||
        field_to_json( Obj,"access",access);
 | 
			
		||||
        field_to_json( Obj,"policy",policy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"users",users);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"resources",resources);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"access",access);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"policy",policy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"users",users);
 | 
			
		||||
            field_from_json( Obj,"resources",resources);
 | 
			
		||||
            field_from_json( Obj,"access",access);
 | 
			
		||||
            field_from_json( Obj,"policy",policy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"users",users);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"resources",resources);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"access",access);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"policy",policy);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -63,17 +60,17 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json(Obj, "entries", entries);
 | 
			
		||||
        field_to_json(Obj, "inUse", inUse);
 | 
			
		||||
        field_to_json(Obj, "entity", entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "inUse", inUse);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "entity", entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json(Obj, "entries", entries);
 | 
			
		||||
            field_from_json(Obj, "inUse", inUse);
 | 
			
		||||
            field_from_json(Obj, "entity", entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "entries", entries);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "inUse", inUse);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "entity", entity);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -83,31 +80,31 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void Entity::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"parent",parent);
 | 
			
		||||
        field_to_json( Obj,"venues",venues);
 | 
			
		||||
        field_to_json( Obj,"children",children);
 | 
			
		||||
        field_to_json( Obj,"contacts",contacts);
 | 
			
		||||
        field_to_json( Obj,"locations",locations);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        field_to_json( Obj,"devices",devices);
 | 
			
		||||
        field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        field_to_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"venues",venues);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"children",children);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"contacts",contacts);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"locations",locations);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"devices",devices);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json( Obj,"parent",parent);
 | 
			
		||||
            field_from_json( Obj,"venues",venues);
 | 
			
		||||
            field_from_json( Obj,"children",children);
 | 
			
		||||
            field_from_json( Obj,"contacts",contacts);
 | 
			
		||||
            field_from_json( Obj,"locations",locations);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            field_from_json( Obj,"devices",devices);
 | 
			
		||||
            field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            field_from_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"venues",venues);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"children",children);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"contacts",contacts);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"locations",locations);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"devices",devices);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -116,14 +113,14 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json( Obj,"parent",parent);
 | 
			
		||||
        field_to_json( Obj,"child",child);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"child",child);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"parent",parent);
 | 
			
		||||
            field_from_json( Obj,"child",child);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"child",child);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
 | 
			
		||||
@@ -133,37 +130,37 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void Venue::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"parent",parent);
 | 
			
		||||
        field_to_json( Obj,"entity",entity);
 | 
			
		||||
        field_to_json( Obj,"children",children);
 | 
			
		||||
        field_to_json( Obj,"devices",devices);
 | 
			
		||||
        field_to_json( Obj,"topology",topology);
 | 
			
		||||
        field_to_json( Obj,"parent",parent);
 | 
			
		||||
        field_to_json( Obj,"design",design);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        field_to_json( Obj,"contact",contact);
 | 
			
		||||
        field_to_json( Obj,"location",location);
 | 
			
		||||
        field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        field_to_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"children",children);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"devices",devices);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"topology",topology);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"design",design);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"contact",contact);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"location",location);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json( Obj,"parent",parent);
 | 
			
		||||
            field_from_json( Obj,"entity",entity);
 | 
			
		||||
            field_from_json( Obj,"children",children);
 | 
			
		||||
            field_from_json( Obj,"devices",devices);
 | 
			
		||||
            field_from_json( Obj,"topology",topology);
 | 
			
		||||
            field_from_json( Obj,"parent",parent);
 | 
			
		||||
            field_from_json( Obj,"design",design);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            field_from_json( Obj,"contact",contact);
 | 
			
		||||
            field_from_json( Obj,"location",location);
 | 
			
		||||
            field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            field_from_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"children",children);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"devices",devices);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"topology",topology);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"design",design);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"contact",contact);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"location",location);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
 | 
			
		||||
@@ -172,16 +169,16 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json( Obj,"id",id);
 | 
			
		||||
        field_to_json( Obj,"entity",loginId);
 | 
			
		||||
        field_to_json( Obj,"children",userType);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"id",id);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",loginId);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"children",userType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"id",id);
 | 
			
		||||
            field_from_json( Obj,"entity",loginId);
 | 
			
		||||
            field_from_json( Obj,"children",userType);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"id",id);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",loginId);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"children",userType);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
        }
 | 
			
		||||
@@ -190,17 +187,17 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        field_to_json( Obj,"users",users);
 | 
			
		||||
        field_to_json( Obj,"entity",entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"users",users);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            field_from_json( Obj,"users",users);
 | 
			
		||||
            field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"users",users);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
        }
 | 
			
		||||
@@ -209,39 +206,39 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void Location::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
 | 
			
		||||
        field_to_json( Obj,"buildingName",buildingName);
 | 
			
		||||
        field_to_json( Obj,"addressLines",addressLines);
 | 
			
		||||
        field_to_json( Obj,"city",city);
 | 
			
		||||
        field_to_json( Obj,"state",state);
 | 
			
		||||
        field_to_json( Obj,"postal",postal);
 | 
			
		||||
        field_to_json( Obj,"country",country);
 | 
			
		||||
        field_to_json( Obj,"phones",phones);
 | 
			
		||||
        field_to_json( Obj,"mobiles",mobiles);
 | 
			
		||||
        field_to_json( Obj,"geoCode",geoCode);
 | 
			
		||||
        field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        field_to_json( Obj,"entity",entity);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"city",city);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"state",state);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"postal",postal);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"country",country);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"phones",phones);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            std::string tmp_type;
 | 
			
		||||
            field_from_json( Obj,"type", tmp_type);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"type", tmp_type);
 | 
			
		||||
            type = location_from_string(tmp_type);
 | 
			
		||||
            field_from_json( Obj,"buildingName",buildingName);
 | 
			
		||||
            field_from_json( Obj,"addressLines",addressLines);
 | 
			
		||||
            field_from_json( Obj,"city",city);
 | 
			
		||||
            field_from_json( Obj,"state",state);
 | 
			
		||||
            field_from_json( Obj,"postal",postal);
 | 
			
		||||
            field_from_json( Obj,"country",country);
 | 
			
		||||
            field_from_json( Obj,"phones",phones);
 | 
			
		||||
            field_from_json( Obj,"mobiles",mobiles);
 | 
			
		||||
            field_from_json( Obj,"geoCode",geoCode);
 | 
			
		||||
            field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            field_from_json( Obj,"entity",entity);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"city",city);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"state",state);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"postal",postal);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"country",country);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"phones",phones);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
 | 
			
		||||
@@ -251,43 +248,43 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void Contact::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"type", to_string(type));
 | 
			
		||||
        field_to_json( Obj,"title",title);
 | 
			
		||||
        field_to_json( Obj,"salutation",salutation);
 | 
			
		||||
        field_to_json( Obj,"firstname",firstname);
 | 
			
		||||
        field_to_json( Obj,"lastname",lastname);
 | 
			
		||||
        field_to_json( Obj,"initials",initials);
 | 
			
		||||
        field_to_json( Obj,"visual",visual);
 | 
			
		||||
        field_to_json( Obj,"mobiles",mobiles);
 | 
			
		||||
        field_to_json( Obj,"phones",phones);
 | 
			
		||||
        field_to_json( Obj,"primaryEmail",primaryEmail);
 | 
			
		||||
        field_to_json( Obj,"secondaryEmail",secondaryEmail);
 | 
			
		||||
        field_to_json( Obj,"accessPIN",accessPIN);
 | 
			
		||||
        field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        field_to_json( Obj,"entity",entity);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"type", to_string(type));
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"title",title);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"salutation",salutation);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"firstname",firstname);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"lastname",lastname);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"initials",initials);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"visual",visual);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"phones",phones);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            std::string tmp_type;
 | 
			
		||||
            field_from_json( Obj,"type", tmp_type);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"type", tmp_type);
 | 
			
		||||
            type = contact_from_string(tmp_type);
 | 
			
		||||
            field_from_json( Obj,"title",title);
 | 
			
		||||
            field_from_json( Obj,"salutation",salutation);
 | 
			
		||||
            field_from_json( Obj,"firstname",firstname);
 | 
			
		||||
            field_from_json( Obj,"lastname",lastname);
 | 
			
		||||
            field_from_json( Obj,"initials",initials);
 | 
			
		||||
            field_from_json( Obj,"visual",visual);
 | 
			
		||||
            field_from_json( Obj,"mobiles",mobiles);
 | 
			
		||||
            field_from_json( Obj,"phones",phones);
 | 
			
		||||
            field_from_json( Obj,"primaryEmail",primaryEmail);
 | 
			
		||||
            field_from_json( Obj,"secondaryEmail",secondaryEmail);
 | 
			
		||||
            field_from_json( Obj,"accessPIN",accessPIN);
 | 
			
		||||
            field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            field_from_json( Obj,"entity",entity);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"title",title);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"salutation",salutation);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"firstname",firstname);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"lastname",lastname);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"initials",initials);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"visual",visual);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"phones",phones);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
 | 
			
		||||
@@ -297,37 +294,35 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json(Obj, "serialNumber", serialNumber);
 | 
			
		||||
        field_to_json(Obj, "venue", venue);
 | 
			
		||||
        field_to_json(Obj, "entity", entity);
 | 
			
		||||
        field_to_json(Obj, "subscriber", subscriber);
 | 
			
		||||
        field_to_json(Obj, "deviceType", deviceType);
 | 
			
		||||
        field_to_json(Obj, "qrCode", qrCode);
 | 
			
		||||
        field_to_json(Obj, "geoCode", geoCode);
 | 
			
		||||
        field_to_json(Obj, "location", location);
 | 
			
		||||
        field_to_json(Obj, "contact", contact);
 | 
			
		||||
        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        field_to_json( Obj,"state",state);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "venue", venue);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "entity", entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "location", location);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "contact", contact);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json( Obj,"serialNumber",serialNumber);
 | 
			
		||||
            field_from_json( Obj,"venue",venue);
 | 
			
		||||
            field_from_json( Obj,"entity",entity);
 | 
			
		||||
            field_from_json( Obj,"subscriber",subscriber);
 | 
			
		||||
            field_from_json( Obj,"deviceType",deviceType);
 | 
			
		||||
            field_from_json(Obj, "qrCode", qrCode);
 | 
			
		||||
            field_from_json( Obj,"geoCode",geoCode);
 | 
			
		||||
            field_from_json( Obj,"location",location);
 | 
			
		||||
            field_from_json( Obj,"contact",contact);
 | 
			
		||||
            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            field_from_json( Obj,"state",state);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"venue",venue);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"location",location);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"contact",contact);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -335,33 +330,19 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
        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 {
 | 
			
		||||
        field_to_json( Obj,"name", name);
 | 
			
		||||
        field_to_json( Obj,"description", description);
 | 
			
		||||
        field_to_json( Obj,"weight", weight);
 | 
			
		||||
        field_to_json( Obj,"configuration", configuration);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"name", name);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"description", description);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"weight", weight);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"configuration", configuration);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool DeviceConfigurationElement::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,"weight",weight);
 | 
			
		||||
            field_from_json( Obj,"configuration",configuration);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"name",name);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"description",description);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"weight",weight);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -371,27 +352,27 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        field_to_json( Obj,"deviceTypes",deviceTypes);
 | 
			
		||||
        field_to_json( Obj,"configuration",configuration);
 | 
			
		||||
        field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        field_to_json( Obj,"variables",variables);
 | 
			
		||||
        field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
			
		||||
        field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"configuration",configuration);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"variables",variables);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            field_from_json( Obj,"deviceTypes",deviceTypes);
 | 
			
		||||
            field_from_json( Obj,"configuration",configuration);
 | 
			
		||||
            field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            field_from_json( Obj,"variables",variables);
 | 
			
		||||
            field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
			
		||||
            field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"variables",variables);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -400,8 +381,8 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Report::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj, "snapshot", snapShot);
 | 
			
		||||
        field_to_json(Obj, "devices", tenants);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "devices", tenants);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void Report::reset() {
 | 
			
		||||
@@ -409,16 +390,16 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj, "uuid", uuid);
 | 
			
		||||
        field_to_json(Obj, "name", name);
 | 
			
		||||
        field_to_json(Obj, "description", description);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "uuid", uuid);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "name", name);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "description", description);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"uuid",uuid);
 | 
			
		||||
            field_from_json( Obj,"name",name);
 | 
			
		||||
            field_from_json( Obj,"description",description);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"uuid",uuid);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"name",name);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"description",description);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -427,14 +408,14 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj, "type", type);
 | 
			
		||||
        field_to_json(Obj, "entries", entries);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "type", type);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"type",type);
 | 
			
		||||
            field_from_json( Obj,"entries",entries);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"type",type);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entries",entries);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -443,157 +424,12 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj, "entries", entries);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json( Obj,"entries",entries);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void UuidList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        field_to_json(Obj, "list", list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool UuidList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json(Obj, "list", list);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, ACLACCESS A) {
 | 
			
		||||
        switch(A) {
 | 
			
		||||
            case READ: Obj.set(FieldName,"read"); break;
 | 
			
		||||
            case MODIFY: Obj.set(FieldName,"modify"); break;
 | 
			
		||||
            case CREATE: Obj.set(FieldName,"create"); break;
 | 
			
		||||
            case DELETE: Obj.set(FieldName,"delete"); break;
 | 
			
		||||
            case NONE:
 | 
			
		||||
                default:
 | 
			
		||||
                    Obj.set(FieldName,"none");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, ACLACCESS &A) {
 | 
			
		||||
        if(Obj->has(FieldName)) {
 | 
			
		||||
            auto V = Obj->getValue<std::string>(FieldName);
 | 
			
		||||
            if(V=="read")
 | 
			
		||||
                A = READ;
 | 
			
		||||
            else if(V=="modify")
 | 
			
		||||
                A = MODIFY;
 | 
			
		||||
            else if(V=="create")
 | 
			
		||||
                A = CREATE;
 | 
			
		||||
            else if(V=="delete")
 | 
			
		||||
                A = DELETE;
 | 
			
		||||
            else if(V=="none")
 | 
			
		||||
                A = NONE;
 | 
			
		||||
            else
 | 
			
		||||
                throw Poco::Exception("invalid JSON");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ObjectACL::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "users", users);
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "roles", roles);
 | 
			
		||||
        field_to_json(Obj, "access", access);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "users", users);
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "roles", roles);
 | 
			
		||||
            field_from_json(Obj, "access", access);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void ObjectACLList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        RESTAPI_utils::field_to_json(Obj, "list", list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            RESTAPI_utils::field_from_json(Obj, "list", list);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string to_string(VISIBILITY A) {
 | 
			
		||||
        switch(A) {
 | 
			
		||||
            case PUBLIC: return "public";
 | 
			
		||||
            case SELECT: return "select";
 | 
			
		||||
            case PRIVATE:
 | 
			
		||||
            default:
 | 
			
		||||
                return "private";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, VISIBILITY A) {
 | 
			
		||||
        Obj.set(FieldName,to_string(A));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VISIBILITY visibility_from_string(const std::string &V) {
 | 
			
		||||
        if(V=="public")
 | 
			
		||||
            return PUBLIC;
 | 
			
		||||
        else if(V=="select")
 | 
			
		||||
            return SELECT;
 | 
			
		||||
        else if(V=="private")
 | 
			
		||||
            return PRIVATE;
 | 
			
		||||
        throw Poco::Exception("invalid json");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, VISIBILITY &A) {
 | 
			
		||||
        if(Obj->has(FieldName)) {
 | 
			
		||||
            auto V = Obj->getValue<std::string>(FieldName);
 | 
			
		||||
            A = visibility_from_string(V);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Map::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        info.to_json(Obj);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"data",data);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"creator",creator);
 | 
			
		||||
        field_to_json( Obj,"visibility",visibility);
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"access",access);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            info.from_json(Obj);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"data",data);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"creator",creator);
 | 
			
		||||
            field_from_json( Obj,"visibility",visibility);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"access",access);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MapList::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
        RESTAPI_utils::field_to_json( Obj,"list",list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"list",list);
 | 
			
		||||
            RESTAPI_utils::field_from_json( Obj,"entries",entries);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch(...) {
 | 
			
		||||
 | 
			
		||||
@@ -602,48 +438,13 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
 | 
			
		||||
        uint64_t Now = std::time(nullptr);
 | 
			
		||||
        if(O->has("name"))
 | 
			
		||||
            I.name = O->get("name").toString();
 | 
			
		||||
 | 
			
		||||
        if(I.name.empty())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if(O->has("description"))
 | 
			
		||||
            I.description = O->get("description").toString();
 | 
			
		||||
        SecurityObjects::MergeNotes(O,U,I.notes);
 | 
			
		||||
        SecurityObjects::NoteInfoVec N;
 | 
			
		||||
        for(auto &i:I.notes) {
 | 
			
		||||
            if(i.note.empty())
 | 
			
		||||
                continue;
 | 
			
		||||
            N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
 | 
			
		||||
        }
 | 
			
		||||
        I.modified = Now;
 | 
			
		||||
        I.modified = std::time(nullptr);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
 | 
			
		||||
        uint64_t Now = std::time(nullptr);
 | 
			
		||||
        if(O->has("name"))
 | 
			
		||||
            I.name = O->get("name").toString();
 | 
			
		||||
 | 
			
		||||
        if(I.name.empty())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if(O->has("description"))
 | 
			
		||||
            I.description = O->get("description").toString();
 | 
			
		||||
 | 
			
		||||
        SecurityObjects::NoteInfoVec N;
 | 
			
		||||
        for(auto &i:I.notes) {
 | 
			
		||||
            if(i.note.empty())
 | 
			
		||||
                continue;
 | 
			
		||||
            N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
 | 
			
		||||
        }
 | 
			
		||||
        I.notes = N;
 | 
			
		||||
        I.modified = I.created = Now;
 | 
			
		||||
        I.id = MicroService::CreateUUID();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -6,20 +6,15 @@
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifndef OWPROV_RESTAPI_PROVOBJECTS_H
 | 
			
		||||
#define OWPROV_RESTAPI_PROVOBJECTS_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::ProvObjects {
 | 
			
		||||
 | 
			
		||||
    enum FIRMWARE_UPGRADE_RULES {
 | 
			
		||||
        dont_upgrade,
 | 
			
		||||
        upgrade_inherit,
 | 
			
		||||
        upgrade_release_only,
 | 
			
		||||
        upgrade_latest
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct ObjectInfo {
 | 
			
		||||
        Types::UUID_t   id;
 | 
			
		||||
        std::string     name;
 | 
			
		||||
@@ -284,22 +279,12 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
        std::string     deviceConfiguration;
 | 
			
		||||
        std::string     rrm;
 | 
			
		||||
        Types::UUID_t   managementPolicy;
 | 
			
		||||
        std::string     state;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
        uint64_t            snapShot=0;
 | 
			
		||||
        Types::CountedMap   tenants;
 | 
			
		||||
@@ -332,59 +317,8 @@ namespace OpenWifi::ProvObjects {
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct UuidList {
 | 
			
		||||
        std::vector<std::string>    list;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum ACLACCESS {
 | 
			
		||||
        NONE, READ, MODIFY, CREATE, DELETE
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct ObjectACL {
 | 
			
		||||
        UuidList        users;
 | 
			
		||||
        UuidList        roles;
 | 
			
		||||
        ACLACCESS       access = NONE;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct ObjectACLList {
 | 
			
		||||
        std::vector<ObjectACL>  list;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum VISIBILITY {
 | 
			
		||||
        PUBLIC, PRIVATE, SELECT
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::string to_string(VISIBILITY A);
 | 
			
		||||
    VISIBILITY visibility_from_string(const std::string &V);
 | 
			
		||||
 | 
			
		||||
    struct Map {
 | 
			
		||||
        ObjectInfo          info;
 | 
			
		||||
        std::string         data;
 | 
			
		||||
        std::string         entity;
 | 
			
		||||
        std::string         creator;
 | 
			
		||||
        VISIBILITY          visibility = PRIVATE;
 | 
			
		||||
        ObjectACLList       access;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct MapList {
 | 
			
		||||
        std::vector<Map>    list;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
 | 
			
		||||
    bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //OWPROV_RESTAPI_PROVOBJECTS_H
 | 
			
		||||
 
 | 
			
		||||
@@ -54,8 +54,6 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
            return ADMIN;
 | 
			
		||||
        else if (!Poco::icompare(U,"subscriber"))
 | 
			
		||||
            return SUBSCRIBER;
 | 
			
		||||
        else if (!Poco::icompare(U,"partner"))
 | 
			
		||||
            return PARTNER;
 | 
			
		||||
        else if (!Poco::icompare(U,"csr"))
 | 
			
		||||
            return CSR;
 | 
			
		||||
        else if (!Poco::icompare(U, "system"))
 | 
			
		||||
@@ -74,7 +72,6 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
            case ROOT: return "root";
 | 
			
		||||
            case ADMIN: return "admin";
 | 
			
		||||
            case SUBSCRIBER: return "subscriber";
 | 
			
		||||
            case PARTNER: return "partner";
 | 
			
		||||
            case CSR: return "csr";
 | 
			
		||||
            case SYSTEM: return "system";
 | 
			
		||||
            case INSTALLER: return "installer";
 | 
			
		||||
@@ -141,7 +138,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
	    field_to_json(Obj,"primary", primary);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
	    try {
 | 
			
		||||
	        field_from_json(Obj,"number",number);
 | 
			
		||||
	        field_from_json(Obj,"verified",verified);
 | 
			
		||||
@@ -158,7 +155,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
	    field_to_json(Obj,"method", method);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
	    try {
 | 
			
		||||
	        field_from_json(Obj,"enabled",enabled);
 | 
			
		||||
	        field_from_json(Obj,"method",method);
 | 
			
		||||
@@ -172,14 +169,12 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
	void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
	    field_to_json(Obj, "mobiles", mobiles);
 | 
			
		||||
	    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 {
 | 
			
		||||
	        field_from_json(Obj, "mobiles",mobiles);
 | 
			
		||||
	        field_from_json(Obj, "mfa",mfa);
 | 
			
		||||
            field_from_json(Obj, "authenticatorSecret", authenticatorSecret);
 | 
			
		||||
	        field_from_json(Obj,"mobiles",mobiles);
 | 
			
		||||
	        field_from_json(Obj,"mfa",mfa);
 | 
			
		||||
	        return true;
 | 
			
		||||
	    } catch (...) {
 | 
			
		||||
 | 
			
		||||
@@ -194,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
        field_to_json(Obj, "method", method);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
    bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
	    try {
 | 
			
		||||
	        field_from_json(Obj,"uuid",uuid);
 | 
			
		||||
	        field_from_json(Obj,"question",question);
 | 
			
		||||
@@ -213,7 +208,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
    bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
            field_from_json(Obj,"uuid",uuid);
 | 
			
		||||
            field_from_json(Obj,"answer",answer);
 | 
			
		||||
@@ -226,7 +221,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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,"description", description);
 | 
			
		||||
		field_to_json(Obj,"avatar", avatar);
 | 
			
		||||
@@ -256,12 +251,11 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
		field_to_json(Obj,"lastPasswords",lastPasswords);
 | 
			
		||||
		field_to_json(Obj,"oauthType",oauthType);
 | 
			
		||||
		field_to_json(Obj,"oauthUserInfo",oauthUserInfo);
 | 
			
		||||
        field_to_json(Obj,"modified",modified);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
        try {
 | 
			
		||||
			field_from_json(Obj,"id",id);
 | 
			
		||||
			field_from_json(Obj,"Id",Id);
 | 
			
		||||
			field_from_json(Obj,"name",name);
 | 
			
		||||
			field_from_json(Obj,"description",description);
 | 
			
		||||
			field_from_json(Obj,"avatar",avatar);
 | 
			
		||||
@@ -271,8 +265,6 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
			field_from_json(Obj,"currentLoginURI",currentLoginURI);
 | 
			
		||||
			field_from_json(Obj,"locale",locale);
 | 
			
		||||
			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(Obj,"securityPolicy",securityPolicy);
 | 
			
		||||
			field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo);
 | 
			
		||||
@@ -291,7 +283,6 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
			field_from_json(Obj,"lastPasswords",lastPasswords);
 | 
			
		||||
			field_from_json(Obj,"oauthType",oauthType);
 | 
			
		||||
			field_from_json(Obj,"oauthUserInfo",oauthUserInfo);
 | 
			
		||||
            field_from_json(Obj,"modified",modified);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (const Poco::Exception &E) {
 | 
			
		||||
 | 
			
		||||
@@ -396,12 +387,11 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
		field_to_json(Obj,"note", note);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"created",created);
 | 
			
		||||
			field_from_json(Obj,"createdBy",createdBy);
 | 
			
		||||
			field_from_json(Obj,"note",note);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch(...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
@@ -438,11 +428,10 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"resource",resource);
 | 
			
		||||
			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch(...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
@@ -458,7 +447,7 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
		field_to_json(Obj,"notes", notes);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"id",id);
 | 
			
		||||
			field_from_json(Obj,"name",name);
 | 
			
		||||
@@ -466,7 +455,6 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
			field_from_json(Obj,"policy",policy);
 | 
			
		||||
			field_from_json(Obj,"role",role);
 | 
			
		||||
			field_from_json(Obj,"notes",notes);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch(...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
@@ -477,126 +465,13 @@ namespace OpenWifi::SecurityObjects {
 | 
			
		||||
		field_to_json(Obj, "profiles", profiles);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj,"profiles",profiles);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch(...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void ActionLink::to_json(Poco::JSON::Object &Obj) const {
 | 
			
		||||
	    field_to_json(Obj,"id",id);
 | 
			
		||||
	    field_to_json(Obj,"action",action);
 | 
			
		||||
	    field_to_json(Obj,"userId",userId);
 | 
			
		||||
	    field_to_json(Obj,"actionTemplate",actionTemplate);
 | 
			
		||||
	    field_to_json(Obj,"variables",variables);
 | 
			
		||||
	    field_to_json(Obj,"locale",locale);
 | 
			
		||||
	    field_to_json(Obj,"message",message);
 | 
			
		||||
	    field_to_json(Obj,"sent",sent);
 | 
			
		||||
	    field_to_json(Obj,"created",created);
 | 
			
		||||
	    field_to_json(Obj,"expires",expires);
 | 
			
		||||
	    field_to_json(Obj,"completed",completed);
 | 
			
		||||
	    field_to_json(Obj,"canceled",canceled);
 | 
			
		||||
        field_to_json(Obj,"userAction",userAction);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
	    try {
 | 
			
		||||
	        field_from_json(Obj,"id",id);
 | 
			
		||||
	        field_from_json(Obj,"action",action);
 | 
			
		||||
	        field_from_json(Obj,"userId",userId);
 | 
			
		||||
	        field_from_json(Obj,"actionTemplate",actionTemplate);
 | 
			
		||||
	        field_from_json(Obj,"variables",variables);
 | 
			
		||||
	        field_from_json(Obj,"locale",locale);
 | 
			
		||||
	        field_from_json(Obj,"message",message);
 | 
			
		||||
	        field_from_json(Obj,"sent",sent);
 | 
			
		||||
	        field_from_json(Obj,"created",created);
 | 
			
		||||
	        field_from_json(Obj,"expires",expires);
 | 
			
		||||
	        field_from_json(Obj,"completed",completed);
 | 
			
		||||
	        field_from_json(Obj,"canceled",canceled);
 | 
			
		||||
            field_from_json(Obj,"userAction",userAction);
 | 
			
		||||
	        return true;
 | 
			
		||||
	    } catch(...) {
 | 
			
		||||
 | 
			
		||||
	    }
 | 
			
		||||
	    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,18 +6,13 @@
 | 
			
		||||
//	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/Data/LOB.h"
 | 
			
		||||
#include "Poco/Data/LOBStream.h"
 | 
			
		||||
#include "../framework/OpenWifiTypes.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    namespace SecurityObjects {
 | 
			
		||||
 | 
			
		||||
        typedef std::string USER_ID_TYPE;
 | 
			
		||||
namespace OpenWifi::SecurityObjects {
 | 
			
		||||
 | 
			
		||||
	struct AclTemplate {
 | 
			
		||||
		bool Read_ = true;
 | 
			
		||||
@@ -47,7 +42,7 @@ namespace OpenWifi {
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
    enum USER_ROLE {
 | 
			
		||||
            UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER
 | 
			
		||||
        UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    USER_ROLE UserTypeFromString(const std::string &U);
 | 
			
		||||
@@ -58,44 +53,43 @@ namespace OpenWifi {
 | 
			
		||||
		std::string createdBy;
 | 
			
		||||
		std::string note;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
	typedef std::vector<NoteInfo>	NoteInfoVec;
 | 
			
		||||
 | 
			
		||||
	struct MobilePhoneNumber {
 | 
			
		||||
	    std::string number;
 | 
			
		||||
            bool verified = false;
 | 
			
		||||
            bool primary = false;
 | 
			
		||||
	    bool verified;
 | 
			
		||||
	    bool primary;
 | 
			
		||||
 | 
			
		||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct MfaAuthInfo {
 | 
			
		||||
            bool enabled = false;
 | 
			
		||||
	    bool enabled;
 | 
			
		||||
	    std::string method;
 | 
			
		||||
 | 
			
		||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct UserLoginLoginExtensions {
 | 
			
		||||
	    std::vector<MobilePhoneNumber>  mobiles;
 | 
			
		||||
	    struct MfaAuthInfo mfa;
 | 
			
		||||
            std::string                     authenticatorSecret;
 | 
			
		||||
 | 
			
		||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct MFAChallengeRequest {
 | 
			
		||||
	    std::string uuid;
 | 
			
		||||
	    std::string question;
 | 
			
		||||
	    std::string method;
 | 
			
		||||
            uint64_t    created = std::time(nullptr);
 | 
			
		||||
	    uint64_t    created;
 | 
			
		||||
 | 
			
		||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
    struct MFAChallengeResponse {
 | 
			
		||||
@@ -103,11 +97,11 @@ namespace OpenWifi {
 | 
			
		||||
        std::string answer;
 | 
			
		||||
 | 
			
		||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
        bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
	struct UserInfo {
 | 
			
		||||
            std::string id;
 | 
			
		||||
        std::string Id;
 | 
			
		||||
		std::string name;
 | 
			
		||||
		std::string description;
 | 
			
		||||
		std::string avatar;
 | 
			
		||||
@@ -134,10 +128,9 @@ namespace OpenWifi {
 | 
			
		||||
		std::string securityPolicy;
 | 
			
		||||
		uint64_t securityPolicyChange = 0 ;
 | 
			
		||||
		std::string currentPassword;
 | 
			
		||||
            OpenWifi::Types::StringVec lastPasswords;
 | 
			
		||||
		Types::StringVec lastPasswords;
 | 
			
		||||
		std::string oauthType;
 | 
			
		||||
		std::string oauthUserInfo;
 | 
			
		||||
            uint64_t    modified;
 | 
			
		||||
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
		bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
@@ -207,7 +200,7 @@ namespace OpenWifi {
 | 
			
		||||
		std::string resource;
 | 
			
		||||
		ResourceAccessType access;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
	typedef std::vector<ProfileAction>	ProfileActionVec;
 | 
			
		||||
 | 
			
		||||
@@ -219,90 +212,15 @@ namespace OpenWifi {
 | 
			
		||||
		std::string role;
 | 
			
		||||
		NoteInfoVec notes;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
	typedef std::vector<SecurityProfile> SecurityProfileVec;
 | 
			
		||||
 | 
			
		||||
	struct SecurityProfileList {
 | 
			
		||||
		SecurityProfileVec profiles;
 | 
			
		||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
			
		||||
            bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
        enum LinkActions {
 | 
			
		||||
            FORGOT_PASSWORD=1,
 | 
			
		||||
            VERIFY_EMAIL,
 | 
			
		||||
            SUB_FORGOT_PASSWORD,
 | 
			
		||||
            SUB_VERIFY_EMAIL
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        struct ActionLink {
 | 
			
		||||
            std::string         id;
 | 
			
		||||
            uint64_t            action;
 | 
			
		||||
            std::string         userId;
 | 
			
		||||
            std::string         actionTemplate;
 | 
			
		||||
            Types::StringPairVec variables;
 | 
			
		||||
            std::string         locale;
 | 
			
		||||
            std::string         message;
 | 
			
		||||
            uint64_t            sent=0;
 | 
			
		||||
            uint64_t            created=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
 | 
			
		||||
@@ -14,19 +14,16 @@
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class SMSSender * SMSSender::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
    int SMSSender::Start() {
 | 
			
		||||
        Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false);
 | 
			
		||||
        if(Enabled_) {
 | 
			
		||||
            Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
 | 
			
		||||
        Provider_ = MicroService::instance().ConfigGetString("sms.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") {
 | 
			
		||||
                ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger());
 | 
			
		||||
            ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
 | 
			
		||||
        }
 | 
			
		||||
        Enabled_ = ProviderImpl_->Initialize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -77,7 +74,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) {
 | 
			
		||||
        if(!Enabled_) {
 | 
			
		||||
            Logger().information("SMS has not been enabled. Messages cannot be sent.");
 | 
			
		||||
            Logger_.information("SMS has not been enabled. Messages cannot be sent.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return ProviderImpl_->Send(PhoneNumber,Message);
 | 
			
		||||
 
 | 
			
		||||
@@ -18,14 +18,16 @@ namespace OpenWifi {
 | 
			
		||||
        std::string Number;
 | 
			
		||||
        std::string Code;
 | 
			
		||||
        std::string UserName;
 | 
			
		||||
        uint64_t    Created = std::time(nullptr);
 | 
			
		||||
        bool        Validated = false;
 | 
			
		||||
        uint64_t    Created;
 | 
			
		||||
        bool        Validated=false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class SMSSender : public SubSystemServer {
 | 
			
		||||
        public:
 | 
			
		||||
            static SMSSender *instance() {
 | 
			
		||||
                static auto *instance_ = new SMSSender;
 | 
			
		||||
                if (instance_ == nullptr) {
 | 
			
		||||
                    instance_ = new SMSSender;
 | 
			
		||||
                }
 | 
			
		||||
                return instance_;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +39,7 @@ namespace OpenWifi {
 | 
			
		||||
            bool IsNumberValid(const std::string &Number, const std::string &UserName);
 | 
			
		||||
            [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
 | 
			
		||||
        private:
 | 
			
		||||
            static SMSSender * instance_;
 | 
			
		||||
            std::string         Provider_;
 | 
			
		||||
            bool                Enabled_=false;
 | 
			
		||||
            std::vector<SMSValidationCacheEntry>    Cache_;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace OpenWifi {
 | 
			
		||||
        Region_ = MicroService::instance().ConfigGetString("smssender.aws.region","");
 | 
			
		||||
 | 
			
		||||
        if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) {
 | 
			
		||||
            Logger().debug("SMSSender is disabled. Please provide key, secret, and region.");
 | 
			
		||||
            Logger_.debug("SMSSender is disabled. Please provide key, secret, and region.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Running_=true;
 | 
			
		||||
@@ -43,7 +43,6 @@ namespace OpenWifi {
 | 
			
		||||
        if(!Running_)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
        Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
 | 
			
		||||
        Aws::SNS::Model::PublishRequest psms_req;
 | 
			
		||||
        psms_req.SetMessage(Message.c_str());
 | 
			
		||||
@@ -51,16 +50,11 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
        auto psms_out = sns.Publish(psms_req);
 | 
			
		||||
        if (psms_out.IsSuccess()) {
 | 
			
		||||
                Logger().debug(Poco::format("SMS sent to %s",PhoneNumber));
 | 
			
		||||
            Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        std::string ErrMsg{psms_out.GetError().GetMessage()};
 | 
			
		||||
            Logger().debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
 | 
			
		||||
            return false;
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        Logger().debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber));
 | 
			
		||||
        Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@ namespace OpenWifi {
 | 
			
		||||
        bool Stop() final ;
 | 
			
		||||
        bool Send(const std::string &Number, const std::string &Message) final;
 | 
			
		||||
        bool Running() final;
 | 
			
		||||
        inline Poco::Logger & Logger() { return Logger_; }
 | 
			
		||||
    private:
 | 
			
		||||
        bool                                Running_=false;
 | 
			
		||||
        Poco::Logger                        &Logger_;
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ namespace OpenWifi {
 | 
			
		||||
        PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber","");
 | 
			
		||||
 | 
			
		||||
        if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) {
 | 
			
		||||
            Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
 | 
			
		||||
            Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Running_=true;
 | 
			
		||||
@@ -64,12 +64,12 @@ namespace OpenWifi {
 | 
			
		||||
        std::istream& rs = session.receiveResponse(res);
 | 
			
		||||
 | 
			
		||||
        if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
 | 
			
		||||
            Logger().information(Poco::format("Message sent to %s", PhoneNumber));
 | 
			
		||||
            Logger_.information(Poco::format("Message sent to %s", PhoneNumber));
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            std::ostringstream os;
 | 
			
		||||
            Poco::StreamCopier::copyStream(rs,os);
 | 
			
		||||
            Logger().information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str()));
 | 
			
		||||
            Logger_.information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str()));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ namespace OpenWifi {
 | 
			
		||||
        bool Stop() final ;
 | 
			
		||||
        bool Send(const std::string &Number, const std::string &Message) final;
 | 
			
		||||
        bool Running() final;
 | 
			
		||||
        inline Poco::Logger & Logger() { return Logger_; }
 | 
			
		||||
    private:
 | 
			
		||||
        bool                                Running_=false;
 | 
			
		||||
        Poco::Logger                        &Logger_;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,19 +9,21 @@
 | 
			
		||||
#include "Poco/Net/SMTPClientSession.h"
 | 
			
		||||
#include "Poco/Net/SecureSMTPClientSession.h"
 | 
			
		||||
#include "Poco/Net/StringPartSource.h"
 | 
			
		||||
#include "Poco/Path.h"
 | 
			
		||||
#include "Poco/Exception.h"
 | 
			
		||||
#include "Poco/Net/SSLManager.h"
 | 
			
		||||
#include "Poco/Net/Context.h"
 | 
			
		||||
#include "Poco/Net/InvalidCertificateHandler.h"
 | 
			
		||||
#include "Poco/Net/AcceptCertificateHandler.h"
 | 
			
		||||
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    class SMTPMailerService * SMTPMailerService::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
    void SMTPMailerService::LoadMyConfig() {
 | 
			
		||||
        Enabled_ = MicroService::instance().ConfigGetBool("mailer.enabled",false);
 | 
			
		||||
        if(Enabled_) {
 | 
			
		||||
        MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
 | 
			
		||||
        SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
 | 
			
		||||
        SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password");
 | 
			
		||||
@@ -29,11 +31,8 @@ namespace OpenWifi {
 | 
			
		||||
        LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod");
 | 
			
		||||
        MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port");
 | 
			
		||||
        TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir());
 | 
			
		||||
            MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60);
 | 
			
		||||
            MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60);
 | 
			
		||||
        Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int SMTPMailerService::Start() {
 | 
			
		||||
        LoadMyConfig();
 | 
			
		||||
@@ -49,52 +48,63 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void SMTPMailerService::reinitialize(Poco::Util::Application &self) {
 | 
			
		||||
        MicroService::instance().LoadConfigurationFile();
 | 
			
		||||
        Logger().information("Reinitializing.");
 | 
			
		||||
        Logger_.information("Reinitializing.");
 | 
			
		||||
        LoadMyConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) {
 | 
			
		||||
        std::lock_guard G(Mutex_);
 | 
			
		||||
        PendingMessages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr),
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        uint64_t Now = std::time(nullptr);
 | 
			
		||||
        std::string RecipientLower = Poco::toLower(Recipient);
 | 
			
		||||
        auto CE = Cache_.find(RecipientLower);
 | 
			
		||||
        if(CE!=Cache_.end()) {
 | 
			
		||||
            // only allow messages to the same user within 2 minutes
 | 
			
		||||
            if(!((CE->second.LastRequest-Now)<30 && CE->second.HowManyRequests<10))
 | 
			
		||||
                return false;
 | 
			
		||||
            if(CE->second.LastRequest-Now>30) {
 | 
			
		||||
                CE->second.LastRequest = Now;
 | 
			
		||||
                CE->second.HowManyRequests=0;
 | 
			
		||||
            } else {
 | 
			
		||||
                CE->second.HowManyRequests++;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Cache_[RecipientLower] = MessageCacheEntry{.LastRequest=Now, .HowManyRequests=0};
 | 
			
		||||
        }
 | 
			
		||||
*/
 | 
			
		||||
        Messages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr),
 | 
			
		||||
                                            .LastTry=0,
 | 
			
		||||
                                            .Sent=0,
 | 
			
		||||
                                            .File=Poco::File(TemplateDir_ + "/" +Name),
 | 
			
		||||
                                            .Attrs=Attrs});
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SMTPMailerService::run() {
 | 
			
		||||
 | 
			
		||||
        Running_ = true;
 | 
			
		||||
        while(Running_) {
 | 
			
		||||
 | 
			
		||||
            Poco::Thread::trySleep(10000);
 | 
			
		||||
            if(!Running_)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
                std::lock_guard G(Mutex_);
 | 
			
		||||
                Messages_.splice(Messages_.end(),PendingMessages_);
 | 
			
		||||
 | 
			
		||||
                uint64_t Now = std::time(nullptr);
 | 
			
		||||
 | 
			
		||||
                for(auto &i:Messages_) {
 | 
			
		||||
                    if(i.Sent==0 && (i.LastTry==0 || (Now-i.LastTry)>120)) {
 | 
			
		||||
                        if (SendIt(i)) {
 | 
			
		||||
                            i.LastTry = i.Sent = std::time(nullptr);
 | 
			
		||||
                        } else
 | 
			
		||||
                            i.LastTry = std::time(nullptr);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            for(auto i=Messages_.begin();i!=Messages_.end();) {
 | 
			
		||||
                if(!Running_)
 | 
			
		||||
                    break;
 | 
			
		||||
                auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second;
 | 
			
		||||
                uint64_t Now = std::time(nullptr);
 | 
			
		||||
                if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) {
 | 
			
		||||
                    if (SendIt(*i)) {
 | 
			
		||||
                        Logger().information(Poco::format("Attempting to deliver for mail '%s'.", Recipient));
 | 
			
		||||
                        i = Messages_.erase(i);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        i->LastTry = Now;
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
                } else if ((Now-i->Posted)>MailAbandon_) {
 | 
			
		||||
                    Logger().information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient));
 | 
			
		||||
                    i = Messages_.erase(i);
 | 
			
		||||
                } else {
 | 
			
		||||
                    ++i;
 | 
			
		||||
                }
 | 
			
		||||
                //  Clean the list
 | 
			
		||||
                std::remove_if(Messages_.begin(),Messages_.end(),[Now](MessageEvent &E){ return (E.Sent!=0 || ((Now-E.LastTry)>(15*60)));});
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -106,12 +116,10 @@ namespace OpenWifi {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SMTPMailerService::SendIt(const MessageEvent &Msg) {
 | 
			
		||||
        std::string             Recipient;
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            Poco::Net::MailMessage  Message;
 | 
			
		||||
            Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
 | 
			
		||||
            std::string             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
 | 
			
		||||
 | 
			
		||||
            auto H1 = Msg.Attrs.find(SENDER);
 | 
			
		||||
            std::string TheSender;
 | 
			
		||||
@@ -121,7 +129,8 @@ namespace OpenWifi {
 | 
			
		||||
                TheSender = Sender_ ;
 | 
			
		||||
            }
 | 
			
		||||
            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.setSubject(Msg.Attrs.find(SUBJECT)->second);
 | 
			
		||||
 | 
			
		||||
@@ -138,26 +147,21 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
            auto Logo = Msg.Attrs.find(LOGO);
 | 
			
		||||
            if(Logo!=Msg.Attrs.end()) {
 | 
			
		||||
                try {
 | 
			
		||||
                    Poco::File          LogoFile(AuthService::GetLogoAssetFileName());
 | 
			
		||||
                Poco::File  LogoFile(TemplateDir_ + "/" + Logo->second);
 | 
			
		||||
                std::ifstream   IF(LogoFile.path());
 | 
			
		||||
                std::ostringstream   OS;
 | 
			
		||||
                Poco::StreamCopier::copyStream(IF, OS);
 | 
			
		||||
                    Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png"));
 | 
			
		||||
                } catch (...) {
 | 
			
		||||
                    Logger().warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName()));
 | 
			
		||||
                Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg"));
 | 
			
		||||
            }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Poco::SharedPtr<Poco::Net::AcceptCertificateHandler>  ptrHandler_ = new Poco::Net::AcceptCertificateHandler(false);
 | 
			
		||||
 | 
			
		||||
            Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_);
 | 
			
		||||
            Poco::Net::Context::Params P;
 | 
			
		||||
            auto ptrContext = Poco::AutoPtr<Poco::Net::Context>
 | 
			
		||||
                    (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "",
 | 
			
		||||
                                                            Poco::Net::Context::VERIFY_RELAXED, 9, true,
 | 
			
		||||
                                                            "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
 | 
			
		||||
            Poco::Net::SSLManager::instance().initializeClient(nullptr,
 | 
			
		||||
                                                               ptrHandler_,
 | 
			
		||||
                                                               &ptrHandler_,
 | 
			
		||||
                                                               ptrContext);
 | 
			
		||||
            session.login();
 | 
			
		||||
            session.startTLS(ptrContext);
 | 
			
		||||
@@ -172,10 +176,7 @@ namespace OpenWifi {
 | 
			
		||||
        }
 | 
			
		||||
        catch (const Poco::Exception& E)
 | 
			
		||||
        {
 | 
			
		||||
            Logger().log(E);
 | 
			
		||||
        }
 | 
			
		||||
        catch (const std::exception &E) {
 | 
			
		||||
            Logger().warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what()));
 | 
			
		||||
            Logger_.log(E);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,9 @@ namespace OpenWifi {
 | 
			
		||||
    class SMTPMailerService : public SubSystemServer, Poco::Runnable {
 | 
			
		||||
        public:
 | 
			
		||||
           static SMTPMailerService *instance() {
 | 
			
		||||
               static auto * instance_ = new SMTPMailerService;
 | 
			
		||||
                if (instance_ == nullptr) {
 | 
			
		||||
                    instance_ = new SMTPMailerService;
 | 
			
		||||
                }
 | 
			
		||||
                return instance_;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -71,35 +73,42 @@ namespace OpenWifi {
 | 
			
		||||
               MessageAttributes    Attrs;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            struct MessageCacheEntry {
 | 
			
		||||
               uint64_t         LastRequest=0;
 | 
			
		||||
               uint64_t         HowManyRequests=0;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            void run() override;
 | 
			
		||||
 | 
			
		||||
            int Start() override;
 | 
			
		||||
            void Stop() override;
 | 
			
		||||
 | 
			
		||||
            bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs);
 | 
			
		||||
            bool SendIt(const MessageEvent &Msg);
 | 
			
		||||
            void LoadMyConfig();
 | 
			
		||||
            void reinitialize(Poco::Util::Application &self) override;
 | 
			
		||||
            bool Enabled() const { return Enabled_; }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            static SMTPMailerService * instance_;
 | 
			
		||||
            std::string             MailHost_;
 | 
			
		||||
            std::string             Sender_;
 | 
			
		||||
            int                     MailHostPort_=25;
 | 
			
		||||
            int                     MailRetry_=2*60;
 | 
			
		||||
            int                     MailAbandon_=2*60*20;
 | 
			
		||||
            std::string             SenderLoginUserName_;
 | 
			
		||||
            std::string             SenderLoginPassword_;
 | 
			
		||||
            std::string             LoginMethod_ = "login";
 | 
			
		||||
            std::string             LogoFileName_;
 | 
			
		||||
            std::string             TemplateDir_;
 | 
			
		||||
            std::list<MessageEvent> Messages_;
 | 
			
		||||
            std::list<MessageEvent> PendingMessages_;
 | 
			
		||||
            std::map<std::string,MessageCacheEntry> Cache_;
 | 
			
		||||
            Poco::Thread            SenderThr_;
 | 
			
		||||
            std::atomic_bool        Running_=false;
 | 
			
		||||
            bool                    Enabled_=false;
 | 
			
		||||
            Poco::Net::AcceptCertificateHandler  ptrHandler_;
 | 
			
		||||
 | 
			
		||||
            SMTPMailerService() noexcept:
 | 
			
		||||
                SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer")
 | 
			
		||||
                SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer"),
 | 
			
		||||
                ptrHandler_(false)
 | 
			
		||||
            {
 | 
			
		||||
                std::string E{"SHA512"};
 | 
			
		||||
            }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,69 +7,22 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "SpecialUserHelpers.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    int StorageService::Start() {
 | 
			
		||||
    class Storage *Storage::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
    int Storage::Start() {
 | 
			
		||||
		std::lock_guard		Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		StorageClass::Start();
 | 
			
		||||
 | 
			
		||||
        UserCache_ = std::make_unique<OpenWifi::UserCache>(64,1200000,true);
 | 
			
		||||
        SubCache_ = std::make_unique<OpenWifi::UserCache>(2048,1200000,false);
 | 
			
		||||
        UserTokenCache_ = std::make_unique<OpenWifi::TokenCache>(64,1200000, true);
 | 
			
		||||
        SubTokenCache_ = std::make_unique<OpenWifi::TokenCache>(2048,1200000,false);
 | 
			
		||||
 | 
			
		||||
        UserDB_ = std::make_unique<OpenWifi::BaseUserDB>("Users", "usr", dbType_,*Pool_, Logger(), UserCache_.get(), true);
 | 
			
		||||
        SubDB_ = std::make_unique<OpenWifi::BaseUserDB>("Subscribers", "sub", dbType_,*Pool_, Logger(), SubCache_.get(), false);
 | 
			
		||||
        UserTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("Tokens", "tok", dbType_,*Pool_, Logger(), UserTokenCache_.get(), true);
 | 
			
		||||
        SubTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("SubTokens", "stk", dbType_,*Pool_, Logger(), SubTokenCache_.get(), false);
 | 
			
		||||
 | 
			
		||||
        PreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("Preferences", "pre", dbType_,*Pool_, Logger());
 | 
			
		||||
        SubPreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("SubPreferences", "prs", dbType_,*Pool_, Logger());
 | 
			
		||||
        ActionLinksDB_ = std::make_unique<OpenWifi::ActionLinkDB>("Actions", "act", dbType_,*Pool_, Logger());
 | 
			
		||||
        AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("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);
 | 
			
		||||
		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes
 | 
			
		||||
		Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours
 | 
			
		||||
		Timer_.start(*Archivercallback_);
 | 
			
		||||
 | 
			
		||||
		Create_Tables();
 | 
			
		||||
		return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void StorageService::Stop() {
 | 
			
		||||
        Logger().notice("Stopping.");
 | 
			
		||||
        Timer_.stop();
 | 
			
		||||
    void Storage::Stop() {
 | 
			
		||||
        Logger_.notice("Stopping.");
 | 
			
		||||
        StorageClass::Stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Archiver::onTimer(Poco::Timer &timer) {
 | 
			
		||||
        Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER");
 | 
			
		||||
        logger.information("Squiggy the DB: removing old tokens.");
 | 
			
		||||
        StorageService()->SubTokenDB().CleanExpiredTokens();
 | 
			
		||||
        StorageService()->UserTokenDB().CleanExpiredTokens();
 | 
			
		||||
        logger.information("Squiggy the DB: removing old actionLinks.");
 | 
			
		||||
        StorageService()->ActionLinksDB().CleanOldActionLinks();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
// namespace
 | 
			
		||||
@@ -13,71 +13,151 @@
 | 
			
		||||
#include "framework/StorageClass.h"
 | 
			
		||||
#include "AuthService.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 {
 | 
			
		||||
 | 
			
		||||
    class Archiver {
 | 
			
		||||
    public:
 | 
			
		||||
        void onTimer(Poco::Timer & timer);
 | 
			
		||||
    private:
 | 
			
		||||
    static const std::string AllActionLinksFieldsForSelect {
 | 
			
		||||
            "Id, "
 | 
			
		||||
            "Action,"
 | 
			
		||||
            "UserId,"
 | 
			
		||||
            "template,"
 | 
			
		||||
            "locale,"
 | 
			
		||||
            "message,"
 | 
			
		||||
            "sent,"
 | 
			
		||||
            "created,"
 | 
			
		||||
            "expires,"
 | 
			
		||||
            "completed,"
 | 
			
		||||
            "canceled"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class StorageService : public StorageClass {
 | 
			
		||||
    static const std::string AllActionLinksFieldsForUpdate {
 | 
			
		||||
            "Id=?, "
 | 
			
		||||
            "Action=?,"
 | 
			
		||||
            "UserId=?,"
 | 
			
		||||
            "template=?,"
 | 
			
		||||
            "locale=?,"
 | 
			
		||||
            "message=?,"
 | 
			
		||||
            "sent=?,"
 | 
			
		||||
            "created=?,"
 | 
			
		||||
            "expires=?,"
 | 
			
		||||
            "completed=?,"
 | 
			
		||||
            "canceled=?"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const std::string AllEmailTemplatesFieldsForCreation {
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const std::string AllEmailTemplatesFieldsForSelect {
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const std::string AllEmailTemplatesFieldsForUpdate {
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class Storage : public StorageClass {
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        static auto instance() {
 | 
			
		||||
            static auto instance_ = new StorageService;
 | 
			
		||||
        enum AUTH_ERROR {
 | 
			
		||||
            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 const 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() {
 | 
			
		||||
            if (instance_ == nullptr) {
 | 
			
		||||
                instance_ = new Storage;
 | 
			
		||||
            }
 | 
			
		||||
            return instance_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int 	Start() override;
 | 
			
		||||
        void 	Stop() override;
 | 
			
		||||
 | 
			
		||||
        OpenWifi::BaseUserDB & UserDB() { return *UserDB_; }
 | 
			
		||||
        OpenWifi::BaseUserDB & SubDB() { return *SubDB_; }
 | 
			
		||||
        OpenWifi::BaseTokenDB & UserTokenDB() { return *UserTokenDB_; }
 | 
			
		||||
        OpenWifi::BaseTokenDB & SubTokenDB() { return *SubTokenDB_; }
 | 
			
		||||
        OpenWifi::PreferencesDB & PreferencesDB() { return *PreferencesDB_; }
 | 
			
		||||
        OpenWifi::PreferencesDB & SubPreferencesDB() { return *SubPreferencesDB_; }
 | 
			
		||||
        OpenWifi::ActionLinkDB & ActionLinksDB() { return *ActionLinksDB_; }
 | 
			
		||||
        OpenWifi::AvatarDB & AvatarDB() { return *AvatarDB_; }
 | 
			
		||||
        OpenWifi::AvatarDB & SubAvatarDB() { return *SubAvatarDB_; }
 | 
			
		||||
        OpenWifi::LoginDB & LoginDB() { return *LoginDB_; }
 | 
			
		||||
        OpenWifi::LoginDB & SubLoginDB() { return *SubLoginDB_; }
 | 
			
		||||
        /*
 | 
			
		||||
         *  All user management functions
 | 
			
		||||
         */
 | 
			
		||||
        bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser);
 | 
			
		||||
        bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
 | 
			
		||||
        bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
 | 
			
		||||
        bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
 | 
			
		||||
        bool SetOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner);
 | 
			
		||||
        bool SetLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location);
 | 
			
		||||
        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 &UserName, 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 CleanRevokedTokens( uint64_t Oldest );
 | 
			
		||||
        bool RevokeAllTokens( std::string & UserName );
 | 
			
		||||
        bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         *  All ActionLinks functions
 | 
			
		||||
         */
 | 
			
		||||
        bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements );
 | 
			
		||||
        bool DeleteAction(std::string &ActionId);
 | 
			
		||||
        bool CompleteAction(std::string &ActionId);
 | 
			
		||||
        bool CancelAction(std::string &ActionId);
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
		static Storage      							*instance_;
 | 
			
		||||
 | 
			
		||||
        std::unique_ptr<OpenWifi::BaseUserDB>           UserDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::BaseUserDB>           SubDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::BaseTokenDB>          UserTokenDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::BaseTokenDB>          SubTokenDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::PreferencesDB>        PreferencesDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::PreferencesDB>        SubPreferencesDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::ActionLinkDB>         ActionLinksDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::AvatarDB>             AvatarDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::AvatarDB>             SubAvatarDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::LoginDB>              LoginDB_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::LoginDB>              SubLoginDB_;
 | 
			
		||||
 | 
			
		||||
        std::unique_ptr<OpenWifi::UserCache>            UserCache_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::UserCache>            SubCache_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::TokenCache>           UserTokenCache_;
 | 
			
		||||
        std::unique_ptr<OpenWifi::TokenCache>           SubTokenCache_;
 | 
			
		||||
 | 
			
		||||
        Poco::Timer                     Timer_;
 | 
			
		||||
        Archiver                        Archiver_;
 | 
			
		||||
        std::unique_ptr<Poco::TimerCallback<Archiver>>   Archivercallback_;
 | 
			
		||||
        int Create_Tables();
 | 
			
		||||
        int Create_UserTable();
 | 
			
		||||
        int Create_AvatarTable();
 | 
			
		||||
        int Create_TokensTable();
 | 
			
		||||
   };
 | 
			
		||||
 | 
			
		||||
    inline auto StorageService() { return StorageService::instance(); };
 | 
			
		||||
    inline Storage * StorageService() { return Storage::instance(); };
 | 
			
		||||
 | 
			
		||||
}  // 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,44 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2021-09-14.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nlohmann/json-schema.hpp>
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
using nlohmann::json;
 | 
			
		||||
using nlohmann::json_schema::json_validator;
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
    class ConfigurationValidator : public  SubSystemServer {
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        static ConfigurationValidator *instance() {
 | 
			
		||||
            if(instance_== nullptr)
 | 
			
		||||
                instance_ = new ConfigurationValidator;
 | 
			
		||||
            return instance_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool Validate(const std::string &C, std::string &Error);
 | 
			
		||||
        static void my_format_checker(const std::string &format, const std::string &value);
 | 
			
		||||
        int Start() override;
 | 
			
		||||
        void Stop() override;
 | 
			
		||||
        void reinitialize(Poco::Util::Application &self) override;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static  ConfigurationValidator * instance_;
 | 
			
		||||
        bool            Initialized_=false;
 | 
			
		||||
        bool            Working_=false;
 | 
			
		||||
        void            Init();
 | 
			
		||||
        std::unique_ptr<json_validator>  Validator_=std::make_unique<json_validator>(nullptr, my_format_checker);
 | 
			
		||||
 | 
			
		||||
        ConfigurationValidator():
 | 
			
		||||
            SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); }
 | 
			
		||||
    inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2,7 +2,8 @@
 | 
			
		||||
// Created by stephane bourque on 2021-10-08.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef OWPROV_COUNTRYCODES_H
 | 
			
		||||
#define OWPROV_COUNTRYCODES_H
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
@@ -269,3 +270,4 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWPROV_COUNTRYCODES_H
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
//	Created by Stephane Bourque on 2021-03-04.
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef UCENTRALGW_KAFKA_TOPICS_H
 | 
			
		||||
#define UCENTRALGW_KAFKA_TOPICS_H
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::KafkaTopics {
 | 
			
		||||
	static const std::string HEALTHCHECK{"healthcheck"};
 | 
			
		||||
@@ -17,7 +17,6 @@ namespace OpenWifi::KafkaTopics {
 | 
			
		||||
	static const std::string COMMAND{"command"};
 | 
			
		||||
	static const std::string SERVICE_EVENTS{"service_events"};
 | 
			
		||||
	static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"};
 | 
			
		||||
	static const std::string DEVICE_TELEMETRY{"device_telemetry"};
 | 
			
		||||
 | 
			
		||||
	namespace ServiceEvents {
 | 
			
		||||
		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,17 +1,25 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 <functional>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#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 {
 | 
			
		||||
    typedef std::pair<std::string,std::string>              StringPair;
 | 
			
		||||
@@ -20,19 +28,15 @@ namespace OpenWifi::Types {
 | 
			
		||||
	typedef std::vector<std::string>						StringVec;
 | 
			
		||||
	typedef std::set<std::string>                           StringSet;
 | 
			
		||||
	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::map<std::string, TopicNotifyFunctionList>  NotifyTable;
 | 
			
		||||
    typedef std::map<std::string,uint64_t>                  CountedMap;
 | 
			
		||||
    typedef std::vector<uint64_t>                           TagList;
 | 
			
		||||
    typedef std::string                                     UUID_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(OpenWifi::Types::CountedMap &M, const std::string &S, uint64_t Increment=1) {
 | 
			
		||||
    inline void UpdateCountedMap(CountedMap &M, const std::string &S, uint64_t Increment=1) {
 | 
			
		||||
        auto it = M.find(S);
 | 
			
		||||
        if(it==M.end())
 | 
			
		||||
            M[S] = Increment;
 | 
			
		||||
@@ -40,21 +44,60 @@ namespace OpenWifi {
 | 
			
		||||
            it->second += Increment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void UpdateCountedMap(OpenWifi::Types::Counted3DMapSII &M, const std::string &S, uint32_t Index, uint64_t Increment=1) {
 | 
			
		||||
        auto it = M.find(S);
 | 
			
		||||
        if(it==M.end()) {
 | 
			
		||||
            std::map<uint32_t,uint64_t> E;
 | 
			
		||||
            E[Index] = Increment;
 | 
			
		||||
            M[S] = E;
 | 
			
		||||
    inline std::string to_string( const StringVec &V) {
 | 
			
		||||
        Poco::JSON::Array   O;
 | 
			
		||||
        for(const auto &i:V) {
 | 
			
		||||
            O.add(i);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            std::map<uint32_t,uint64_t> & IndexMap = it->second;
 | 
			
		||||
            auto it_index = IndexMap.find(Index);
 | 
			
		||||
            if(it_index == IndexMap.end()) {
 | 
			
		||||
                IndexMap[Index] = Increment;
 | 
			
		||||
            } else {
 | 
			
		||||
                it_index->second += Increment;
 | 
			
		||||
        std::stringstream SS;
 | 
			
		||||
        Poco::JSON::Stringifier::stringify(O,SS);
 | 
			
		||||
        return SS.str();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline std::string to_string( const StringPairVec &V) {
 | 
			
		||||
        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.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef OWPROV_RESTAPI_ERRORS_H
 | 
			
		||||
#define OWPROV_RESTAPI_ERRORS_H
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::RESTAPI::Errors {
 | 
			
		||||
    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 NameMustBeSet{"The name property must be set."};
 | 
			
		||||
    static const std::string ConfigBlockInvalid{"Configuration block type invalid."};
 | 
			
		||||
    static const std::string UnknownId{"Unknown UUID."};
 | 
			
		||||
    static const std::string UnknownId{"Unknown management policy."};
 | 
			
		||||
    static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."};
 | 
			
		||||
    static const std::string RecordNotCreated{"Record could not be created."};
 | 
			
		||||
    static const std::string RecordNotUpdated{"Record could not be updated."};
 | 
			
		||||
@@ -46,23 +47,13 @@ namespace OpenWifi::RESTAPI::Errors {
 | 
			
		||||
    static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
 | 
			
		||||
    static const std::string InvalidUserRole{"Invalid userRole."};
 | 
			
		||||
    static const std::string InvalidEmailAddress{"Invalid email address."};
 | 
			
		||||
    static const std::string InvalidPassword{"Invalid password."};
 | 
			
		||||
    static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
 | 
			
		||||
    static const std::string InvalidIPRanges{"Invalid IP range specifications."};
 | 
			
		||||
    static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
 | 
			
		||||
    static const std::string NeedMobileNumber{"You must provide at least one validated phone number."};
 | 
			
		||||
    static const std::string BadMFAMethod{"MFA only supports sms or email."};
 | 
			
		||||
    static const std::string InvalidCredentials{"Invalid credentials (username/password)."};
 | 
			
		||||
    static const std::string InvalidPassword{"Password does not conform to basic password rules."};
 | 
			
		||||
    static const std::string UserPendingVerification{"User access denied pending email verification."};
 | 
			
		||||
    static const std::string PasswordMustBeChanged{"Password must be changed."};
 | 
			
		||||
    static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
 | 
			
		||||
    static const std::string MissingAuthenticationInformation{"Missing authentication information."};
 | 
			
		||||
    static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
 | 
			
		||||
    static const std::string ExpiredToken{"Token has expired, user must login."};
 | 
			
		||||
    static const std::string SubscriberMustExist{"Subscriber must exist."};
 | 
			
		||||
    static const std::string AuthenticatorVerificationIncomplete{"Authenticator validation is not complete."};
 | 
			
		||||
    static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."};
 | 
			
		||||
    static const std::string SMSCouldNotValidate{"Code and number could not be validated"};
 | 
			
		||||
    static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWPROV_RESTAPI_ERRORS_H
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user