mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-11-03 20:27:45 +00:00 
			
		
		
		
	Compare commits
	
		
			45 Commits
		
	
	
		
			release/v2
			...
			feature/wi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					05d06fce53 | ||
| 
						 | 
					eaac1f1625 | ||
| 
						 | 
					c5f4c067bb | ||
| 
						 | 
					31a9e4564b | ||
| 
						 | 
					a9affc29bb | ||
| 
						 | 
					65fc0a1d10 | ||
| 
						 | 
					82c01ce438 | ||
| 
						 | 
					5f900883e8 | ||
| 
						 | 
					e97b8e64be | ||
| 
						 | 
					6c90c75708 | ||
| 
						 | 
					a3d86c7cf9 | ||
| 
						 | 
					50b6ac9522 | ||
| 
						 | 
					15b947a34d | ||
| 
						 | 
					160bd00a99 | ||
| 
						 | 
					3c7daa537a | ||
| 
						 | 
					c5bab1d749 | ||
| 
						 | 
					96c3244be0 | ||
| 
						 | 
					7e4b515f60 | ||
| 
						 | 
					a63f80e497 | ||
| 
						 | 
					2eae6cc73c | ||
| 
						 | 
					96f215b3c2 | ||
| 
						 | 
					9551384358 | ||
| 
						 | 
					b21c5c5e00 | ||
| 
						 | 
					031d35256c | ||
| 
						 | 
					5738fa47bb | ||
| 
						 | 
					fe17650333 | ||
| 
						 | 
					7636568fb4 | ||
| 
						 | 
					c0ef77eb53 | ||
| 
						 | 
					00742a5d0a | ||
| 
						 | 
					a96f673380 | ||
| 
						 | 
					53ecdb471e | ||
| 
						 | 
					f80a0c5007 | ||
| 
						 | 
					9e7d7ba67d | ||
| 
						 | 
					b508c0d054 | ||
| 
						 | 
					79788dab44 | ||
| 
						 | 
					8dec946c45 | ||
| 
						 | 
					43ea5ac424 | ||
| 
						 | 
					328ff158cb | ||
| 
						 | 
					2b89d843c3 | ||
| 
						 | 
					45a50483be | ||
| 
						 | 
					c8ae94a062 | ||
| 
						 | 
					7b19143d6f | ||
| 
						 | 
					bc0c889098 | ||
| 
						 | 
					6f8f81866f | ||
| 
						 | 
					f213c99816 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -18,3 +18,4 @@ _deps
 | 
				
			|||||||
*.csr
 | 
					*.csr
 | 
				
			||||||
/cmake-build/
 | 
					/cmake-build/
 | 
				
			||||||
/smake-build-debug/
 | 
					/smake-build-debug/
 | 
				
			||||||
 | 
					test_scripts/curl/result.json
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.13)
 | 
					cmake_minimum_required(VERSION 3.13)
 | 
				
			||||||
project(owsec VERSION 2.3.0)
 | 
					project(owsec VERSION 2.4.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_STANDARD 17)
 | 
					set(CMAKE_CXX_STANDARD 17)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,7 +42,7 @@ find_package(Boost REQUIRED system)
 | 
				
			|||||||
find_package(OpenSSL REQUIRED)
 | 
					find_package(OpenSSL REQUIRED)
 | 
				
			||||||
find_package(ZLIB REQUIRED)
 | 
					find_package(ZLIB REQUIRED)
 | 
				
			||||||
find_package(AWSSDK     REQUIRED COMPONENTS sns)
 | 
					find_package(AWSSDK     REQUIRED COMPONENTS sns)
 | 
				
			||||||
 | 
					find_package(nlohmann_json  REQUIRED)
 | 
				
			||||||
find_package(CppKafka REQUIRED)
 | 
					find_package(CppKafka REQUIRED)
 | 
				
			||||||
find_package(PostgreSQL REQUIRED)
 | 
					find_package(PostgreSQL REQUIRED)
 | 
				
			||||||
find_package(MySQL REQUIRED)
 | 
					find_package(MySQL REQUIRED)
 | 
				
			||||||
@@ -86,7 +86,11 @@ add_executable( owsec
 | 
				
			|||||||
        src/MFAServer.cpp src/MFAServer.h
 | 
					        src/MFAServer.cpp src/MFAServer.h
 | 
				
			||||||
        src/SMS_provider_aws.cpp src/SMS_provider_aws.h
 | 
					        src/SMS_provider_aws.cpp src/SMS_provider_aws.h
 | 
				
			||||||
        src/SMS_provider.cpp src/SMS_provider.h
 | 
					        src/SMS_provider.cpp src/SMS_provider.h
 | 
				
			||||||
        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h)
 | 
					        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
 | 
				
			||||||
 | 
					        src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
 | 
				
			||||||
 | 
					        src/storage/storage_tokens.h
 | 
				
			||||||
 | 
					        src/ActionLinkManager.cpp src/ActionLinkManager.h
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(NOT SMALL_BUILD)
 | 
					if(NOT SMALL_BUILD)
 | 
				
			||||||
    target_link_libraries(owsec PUBLIC
 | 
					    target_link_libraries(owsec PUBLIC
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -11,6 +11,8 @@ RUN apk add --update --no-cache \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
RUN git clone https://github.com/stephb9959/poco /poco
 | 
					RUN git clone https://github.com/stephb9959/poco /poco
 | 
				
			||||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
 | 
					RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
 | 
				
			||||||
 | 
					RUN git clone https://github.com/nlohmann/json /json
 | 
				
			||||||
 | 
					RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
 | 
				
			||||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
 | 
					RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /aws-sdk-cpp
 | 
					WORKDIR /aws-sdk-cpp
 | 
				
			||||||
@@ -37,6 +39,20 @@ RUN cmake ..
 | 
				
			|||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /json
 | 
				
			||||||
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
 | 
					WORKDIR cmake-build
 | 
				
			||||||
 | 
					RUN cmake ..
 | 
				
			||||||
 | 
					RUN make
 | 
				
			||||||
 | 
					RUN make install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /json-schema-validator
 | 
				
			||||||
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
 | 
					WORKDIR cmake-build
 | 
				
			||||||
 | 
					RUN cmake ..
 | 
				
			||||||
 | 
					RUN make
 | 
				
			||||||
 | 
					RUN make install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD CMakeLists.txt build /owsec/
 | 
					ADD CMakeLists.txt build /owsec/
 | 
				
			||||||
ADD cmake /owsec/cmake
 | 
					ADD cmake /owsec/cmake
 | 
				
			||||||
ADD src /owsec/src
 | 
					ADD src /owsec/src
 | 
				
			||||||
@@ -75,6 +91,7 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
 | 
				
			|||||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
					    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY readiness_check /readiness_check
 | 
					COPY readiness_check /readiness_check
 | 
				
			||||||
 | 
					COPY test_scripts/curl/cli /cli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPOSE 16001 17001 16101
 | 
					EXPOSE 16001 17001 16101
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README.md
									
									
									
									
									
								
							@@ -98,6 +98,40 @@ to get a sample. The default is
 | 
				
			|||||||
### `authentication.oldpasswords`
 | 
					### `authentication.oldpasswords`
 | 
				
			||||||
The number of older passwords to keep. Default is 5.
 | 
					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
 | 
					### 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
 | 
					This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
 | 
				
			||||||
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
 | 
					in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,9 @@ spec:
 | 
				
			|||||||
    metadata:
 | 
					    metadata:
 | 
				
			||||||
      annotations:
 | 
					      annotations:
 | 
				
			||||||
        checksum/config: {{ include "owsec.config" . | sha256sum }}
 | 
					        checksum/config: {{ include "owsec.config" . | sha256sum }}
 | 
				
			||||||
 | 
					        {{- with .Values.podAnnotations }}
 | 
				
			||||||
 | 
					        {{- toYaml . | nindent 8 }}
 | 
				
			||||||
 | 
					        {{- end }}
 | 
				
			||||||
      labels:
 | 
					      labels:
 | 
				
			||||||
        app.kubernetes.io/name: {{ include "owsec.name" . }}
 | 
					        app.kubernetes.io/name: {{ include "owsec.name" . }}
 | 
				
			||||||
        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
					        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,6 +95,8 @@ tolerations: []
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
affinity: {}
 | 
					affinity: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					podAnnotations: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
persistence:
 | 
					persistence:
 | 
				
			||||||
  enabled: true
 | 
					  enabled: true
 | 
				
			||||||
  # storageClassName: "-"
 | 
					  # storageClassName: "-"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,16 @@ components:
 | 
				
			|||||||
            properties:
 | 
					            properties:
 | 
				
			||||||
              ErrorCode:
 | 
					              ErrorCode:
 | 
				
			||||||
                type: integer
 | 
					                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
 | 
				
			||||||
              ErrorDetails:
 | 
					              ErrorDetails:
 | 
				
			||||||
                type: string
 | 
					                type: string
 | 
				
			||||||
              ErrorDescription:
 | 
					              ErrorDescription:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								src/ActionLinkManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/ActionLinkManager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// 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()->GetActions(Links);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(Links.empty())
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for(auto &i:Links) {
 | 
				
			||||||
 | 
					                if(!Running_)
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
 | 
					                if(!StorageService()->GetUserById(i.userId,UInfo)) {
 | 
				
			||||||
 | 
					                    StorageService()->CancelAction(i.id);
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(i.action==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()->SentAction(i.id);
 | 
				
			||||||
 | 
					                } else if (i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) {
 | 
				
			||||||
 | 
					                    if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
 | 
				
			||||||
 | 
					                        Logger_.information(Poco::format("Send email verification link to %s",UInfo.email));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    StorageService()->SentAction(i.id);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    StorageService()->SentAction(i.id);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/ActionLinkManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/ActionLinkManager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static ActionLinkManager * instance() {
 | 
				
			||||||
 | 
					            static ActionLinkManager instance;
 | 
				
			||||||
 | 
					            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,6 +11,7 @@
 | 
				
			|||||||
#include "Poco/Net/OAuth20Credentials.h"
 | 
					#include "Poco/Net/OAuth20Credentials.h"
 | 
				
			||||||
#include "Poco/JWT/Token.h"
 | 
					#include "Poco/JWT/Token.h"
 | 
				
			||||||
#include "Poco/JWT/Signer.h"
 | 
					#include "Poco/JWT/Signer.h"
 | 
				
			||||||
 | 
					#include "Poco/StringTokenizer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
@@ -21,7 +22,6 @@
 | 
				
			|||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class AuthService *AuthService::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
 | 
					    AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
 | 
				
			||||||
		switch (C) {
 | 
							switch (C) {
 | 
				
			||||||
@@ -46,10 +46,6 @@ namespace OpenWifi {
 | 
				
			|||||||
		Signer_.setRSAKey(MicroService::instance().Key());
 | 
							Signer_.setRSAKey(MicroService::instance().Key());
 | 
				
			||||||
		Signer_.addAllAlgorithms();
 | 
							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,}$");
 | 
					        PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
 | 
				
			||||||
        TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
 | 
					        TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
 | 
				
			||||||
        HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
 | 
					        HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
 | 
				
			||||||
@@ -62,39 +58,41 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo )
 | 
						bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo )
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if(!Secure_)
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::lock_guard	Guard(Mutex_);
 | 
					        std::lock_guard	Guard(Mutex_);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::string CallToken;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
 | 
							    std::string CallToken;
 | 
				
			||||||
		    Poco::Net::OAuth20Credentials Auth(Request);
 | 
							    Poco::Net::OAuth20Credentials Auth(Request);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		    if (Auth.getScheme() == "Bearer") {
 | 
							    if (Auth.getScheme() == "Bearer") {
 | 
				
			||||||
		        CallToken = Auth.getBearerToken();
 | 
							        CallToken = Auth.getBearerToken();
 | 
				
			||||||
		    }
 | 
							    }
 | 
				
			||||||
		} catch(const Poco::Exception &E) {
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		    if(!CallToken.empty()) {
 | 
							    if(!CallToken.empty()) {
 | 
				
			||||||
		        if(StorageService()->IsTokenRevoked(CallToken))
 | 
							        if(StorageService()->IsTokenRevoked(CallToken))
 | 
				
			||||||
		            return false;
 | 
							            return false;
 | 
				
			||||||
		        auto Client = UserCache_.find(CallToken);
 | 
							        auto Client = UserCache_.find(CallToken);
 | 
				
			||||||
		    if( Client == UserCache_.end() )
 | 
							        if( Client == UserCache_.end() ) {
 | 
				
			||||||
		        return ValidateToken(CallToken, CallToken, UInfo);
 | 
							            if(StorageService()->GetToken(SessionToken,UInfo)) {
 | 
				
			||||||
 | 
							                if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
 | 
				
			||||||
 | 
							                    UserCache_[UInfo.webtoken.access_token_] = UInfo;
 | 
				
			||||||
 | 
							                    return true;
 | 
				
			||||||
 | 
							                }
 | 
				
			||||||
 | 
							            }
 | 
				
			||||||
 | 
							            return false;
 | 
				
			||||||
 | 
							        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		        if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
 | 
							        if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
 | 
				
			||||||
		            SessionToken = CallToken;
 | 
							            SessionToken = CallToken;
 | 
				
			||||||
		            UInfo = Client->second ;
 | 
							            UInfo = Client->second ;
 | 
				
			||||||
		            return true;
 | 
							            return true;
 | 
				
			||||||
		        }
 | 
							        }
 | 
				
			||||||
		    UserCache_.erase(CallToken);
 | 
					
 | 
				
			||||||
 | 
							        UserCache_.erase(Client);
 | 
				
			||||||
		        StorageService()->RevokeToken(CallToken);
 | 
							        StorageService()->RevokeToken(CallToken);
 | 
				
			||||||
		        return false;
 | 
							        return false;
 | 
				
			||||||
		    }
 | 
							    }
 | 
				
			||||||
 | 
							} catch(const Poco::Exception &E) {
 | 
				
			||||||
 | 
							    Logger_.log(E);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -168,28 +166,6 @@ namespace OpenWifi {
 | 
				
			|||||||
		return JWT;
 | 
							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)
 | 
					    void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard		Guard(Mutex_);
 | 
					        std::lock_guard		Guard(Mutex_);
 | 
				
			||||||
@@ -215,35 +191,80 @@ namespace OpenWifi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
 | 
					    bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
 | 
				
			||||||
        auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword);
 | 
					        std::lock_guard     G(Mutex_);
 | 
				
			||||||
        for (auto const &i:UInfo.lastPasswords) {
 | 
					
 | 
				
			||||||
            if (i == NewPasswordHash) {
 | 
					        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;
 | 
					                            return false;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                SHA2_.update(NewPassword+UInfo.email);
 | 
				
			||||||
 | 
					                if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
 | 
					        if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
 | 
				
			||||||
            UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
 | 
					            UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        UInfo.lastPasswords.push_back(NewPasswordHash);
 | 
					
 | 
				
			||||||
        UInfo.currentPassword = NewPasswordHash;
 | 
					        auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
 | 
				
			||||||
 | 
					        UInfo.lastPasswords.push_back(NewHash);
 | 
				
			||||||
 | 
					        UInfo.currentPassword = NewHash;
 | 
				
			||||||
        UInfo.changePassword = false;
 | 
					        UInfo.changePassword = false;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard		Guard(Mutex_);
 | 
					        std::lock_guard		Guard(Mutex_);
 | 
				
			||||||
        SecurityObjects::AclTemplate	ACL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(UserName);
 | 
					        Poco::toLowerInPlace(UserName);
 | 
				
			||||||
        auto PasswordHash = ComputePasswordHash(UserName, Password);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
 | 
					        if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
 | 
				
			||||||
            if(UInfo.userinfo.waitingForEmailCheck) {
 | 
					            if(UInfo.userinfo.waitingForEmailCheck) {
 | 
				
			||||||
                return USERNAME_PENDING_VERIFICATION;
 | 
					                return USERNAME_PENDING_VERIFICATION;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(PasswordHash != UInfo.userinfo.currentPassword) {
 | 
					            if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
 | 
				
			||||||
                return INVALID_CREDENTIALS;
 | 
					                return INVALID_CREDENTIALS;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,51 +294,31 @@ namespace OpenWifi {
 | 
				
			|||||||
            return SUCCESS;
 | 
					            return SUCCESS;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            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;
 | 
					        return INVALID_CREDENTIALS;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) {
 | 
					    bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
 | 
				
			||||||
        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;
 | 
					        SecurityObjects::UserInfo   UInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(StorageService()->GetUserByEmail(Email,UInfo)) {
 | 
					        if(StorageService()->GetUserByEmail(Email,UInfo)) {
 | 
				
			||||||
            switch (Reason) {
 | 
					            switch (Reason) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case FORGOT_PASSWORD: {
 | 
					                case FORGOT_PASSWORD: {
 | 
				
			||||||
                        MessageAttributes Attrs;
 | 
					                        MessageAttributes Attrs;
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
					                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
				
			||||||
                        Attrs[LOGO] = "logo.jpg";
 | 
					                        Attrs[LOGO] = GetLogoAssetURI();
 | 
				
			||||||
                        Attrs[SUBJECT] = "Password reset link";
 | 
					                        Attrs[SUBJECT] = "Password reset link";
 | 
				
			||||||
                        Attrs[ACTION_LINK] =
 | 
					                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
 | 
				
			||||||
                                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
 | 
					 | 
				
			||||||
                        SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
 | 
					                        SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case EMAIL_VERIFICATION: {
 | 
					                case EMAIL_VERIFICATION: {
 | 
				
			||||||
                        MessageAttributes Attrs;
 | 
					                        MessageAttributes Attrs;
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
					                        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
				
			||||||
                        Attrs[LOGO] = "logo.jpg";
 | 
					                        Attrs[LOGO] = GetLogoAssetURI();
 | 
				
			||||||
                        Attrs[SUBJECT] = "EMail Address Verification";
 | 
					                        Attrs[SUBJECT] = "EMail Address Verification";
 | 
				
			||||||
                        Attrs[ACTION_LINK] =
 | 
					                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
 | 
				
			||||||
                                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
 | 
					 | 
				
			||||||
                        SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
 | 
					                        SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
 | 
				
			||||||
                        UInfo.waitingForEmailCheck = true;
 | 
					                        UInfo.waitingForEmailCheck = true;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -326,19 +327,20 @@ namespace OpenWifi {
 | 
				
			|||||||
                default:
 | 
					                default:
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
 | 
					    bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
 | 
				
			||||||
        MessageAttributes Attrs;
 | 
					        SecurityObjects::ActionLink A;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
					        A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
 | 
				
			||||||
        Attrs[LOGO] = "logo.jpg";
 | 
					        A.userId = UInfo.email;
 | 
				
			||||||
        Attrs[SUBJECT] = "EMail Address Verification";
 | 
					        A.id = MicroService::instance().CreateUUID();
 | 
				
			||||||
        Attrs[ACTION_LINK] =
 | 
					        A.created = std::time(nullptr);
 | 
				
			||||||
                MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
 | 
					        A.expires = A.created + 24*60*60;
 | 
				
			||||||
        SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
 | 
					        StorageService()->CreateAction(A);
 | 
				
			||||||
        UInfo.waitingForEmailCheck = true;
 | 
					        UInfo.waitingForEmailCheck = true;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,16 +35,6 @@ namespace OpenWifi{
 | 
				
			|||||||
            CUSTOM
 | 
					            CUSTOM
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        enum AUTH_ERROR {
 | 
					 | 
				
			||||||
            SUCCESS,
 | 
					 | 
				
			||||||
            PASSWORD_CHANGE_REQUIRED,
 | 
					 | 
				
			||||||
            INVALID_CREDENTIALS,
 | 
					 | 
				
			||||||
            PASSWORD_ALREADY_USED,
 | 
					 | 
				
			||||||
            USERNAME_PENDING_VERIFICATION,
 | 
					 | 
				
			||||||
            PASSWORD_INVALID,
 | 
					 | 
				
			||||||
            INTERNAL_ERROR
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        enum EMAIL_REASON {
 | 
					        enum EMAIL_REASON {
 | 
				
			||||||
            FORGOT_PASSWORD,
 | 
					            FORGOT_PASSWORD,
 | 
				
			||||||
            EMAIL_VERIFICATION
 | 
					            EMAIL_VERIFICATION
 | 
				
			||||||
@@ -54,19 +44,16 @@ namespace OpenWifi{
 | 
				
			|||||||
        static int AccessTypeToInt(ACCESS_TYPE T);
 | 
					        static int AccessTypeToInt(ACCESS_TYPE T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static AuthService *instance() {
 | 
					        static AuthService *instance() {
 | 
				
			||||||
            if (instance_ == nullptr) {
 | 
					            static AuthService instance;
 | 
				
			||||||
                instance_ = new AuthService;
 | 
					            return &instance;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return instance_;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int Start() override;
 | 
					        int Start() override;
 | 
				
			||||||
        void Stop() override;
 | 
					        void Stop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
 | 
					        [[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 );
 | 
					        [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo );
 | 
				
			||||||
        void CreateToken(const std::string & UserName, 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]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
				
			||||||
        [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
					        [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
				
			||||||
        void Logout(const std::string &token, bool EraseFromCache=true);
 | 
					        void Logout(const std::string &token, bool EraseFromCache=true);
 | 
				
			||||||
@@ -77,22 +64,27 @@ namespace OpenWifi{
 | 
				
			|||||||
        [[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
 | 
					        [[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
 | 
				
			||||||
        [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
 | 
					        [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
 | 
				
			||||||
        [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
 | 
					        [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
 | 
				
			||||||
        [[nodiscard]] 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]] 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 UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
					        [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
				
			||||||
        [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
 | 
					        [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
 | 
					        [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
 | 
				
			||||||
        [[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason);
 | 
					        [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
 | 
				
			||||||
        [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
 | 
					        [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
 | 
				
			||||||
        [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
					        [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [[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().DataDir() + "/wwwassets/the_logo.png";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
		static AuthService *instance_;
 | 
					 | 
				
			||||||
		bool    			Secure_ = false ;
 | 
					 | 
				
			||||||
		std::string     	DefaultUserName_;
 | 
					 | 
				
			||||||
		std::string			DefaultPassword_;
 | 
					 | 
				
			||||||
		std::string     	Mechanism_;
 | 
					 | 
				
			||||||
		Poco::JWT::Signer	Signer_;
 | 
							Poco::JWT::Signer	Signer_;
 | 
				
			||||||
		Poco::SHA2Engine	SHA2_;
 | 
							Poco::SHA2Engine	SHA2_;
 | 
				
			||||||
		SecurityObjects::UserInfoCache UserCache_;
 | 
							SecurityObjects::UserInfoCache UserCache_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@
 | 
				
			|||||||
#include "SMTPMailerService.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
#include "AuthService.h"
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
 | 
					#include "ActionLinkManager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class Daemon *Daemon::instance_ = nullptr;
 | 
					    class Daemon *Daemon::instance_ = nullptr;
 | 
				
			||||||
@@ -44,7 +45,9 @@ namespace OpenWifi {
 | 
				
			|||||||
                                   SubSystemVec{
 | 
					                                   SubSystemVec{
 | 
				
			||||||
                                           StorageService(),
 | 
					                                           StorageService(),
 | 
				
			||||||
                                           SMSSender(),
 | 
					                                           SMSSender(),
 | 
				
			||||||
 | 
					                                           ActionLinkManager(),
 | 
				
			||||||
                                           SMTPMailerService(),
 | 
					                                           SMTPMailerService(),
 | 
				
			||||||
 | 
					                                           RESTAPI_RateLimiter(),
 | 
				
			||||||
                                           AuthService()
 | 
					                                           AuthService()
 | 
				
			||||||
                                   });
 | 
					                                   });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -53,8 +56,8 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void Daemon::initialize() {
 | 
					    void Daemon::initialize() {
 | 
				
			||||||
        AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
					        AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
				
			||||||
        AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
 | 
					        AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html");
 | 
				
			||||||
        PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
 | 
					        PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void MicroServicePostInitialization() {
 | 
					    void MicroServicePostInitialization() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,10 @@
 | 
				
			|||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "AuthService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class MFAServer * MFAServer::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int MFAServer::Start() {
 | 
					    int MFAServer::Start() {
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -47,7 +46,7 @@ namespace OpenWifi {
 | 
				
			|||||||
        if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
 | 
					        if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
 | 
				
			||||||
            MessageAttributes Attrs;
 | 
					            MessageAttributes Attrs;
 | 
				
			||||||
            Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
 | 
					            Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
 | 
				
			||||||
            Attrs[LOGO] = "logo.jpg";
 | 
					            Attrs[LOGO] = AuthService::GetLogoAssetURI();
 | 
				
			||||||
            Attrs[SUBJECT] = "Login validation code";
 | 
					            Attrs[SUBJECT] = "Login validation code";
 | 
				
			||||||
            Attrs[CHALLENGE_CODE] = Challenge;
 | 
					            Attrs[CHALLENGE_CODE] = Challenge;
 | 
				
			||||||
            return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
 | 
					            return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,24 +24,21 @@ namespace OpenWifi {
 | 
				
			|||||||
        int Start() override;
 | 
					        int Start() override;
 | 
				
			||||||
        void Stop() override;
 | 
					        void Stop() override;
 | 
				
			||||||
        static MFAServer *instance() {
 | 
					        static MFAServer *instance() {
 | 
				
			||||||
            if (instance_ == nullptr) {
 | 
					            static MFAServer instance;
 | 
				
			||||||
                instance_ = new MFAServer;
 | 
					            return &instance;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return instance_;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
 | 
					        bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
 | 
				
			||||||
        bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
					        bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
        bool MethodEnabled(const std::string &Method);
 | 
					        static bool MethodEnabled(const std::string &Method);
 | 
				
			||||||
        bool ResendCode(const std::string &uuid);
 | 
					        bool ResendCode(const std::string &uuid);
 | 
				
			||||||
        bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
					        static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static inline std::string MakeChallenge() {
 | 
					        static inline std::string MakeChallenge() {
 | 
				
			||||||
            return std::to_string(rand() % 999999);
 | 
					            return std::to_string(rand() % 999999);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        static MFAServer *  instance_;
 | 
					 | 
				
			||||||
        MFAChallengeCache   Cache_;
 | 
					        MFAChallengeCache   Cache_;
 | 
				
			||||||
        MFAServer() noexcept:
 | 
					        MFAServer() noexcept:
 | 
				
			||||||
            SubSystemServer("MFServer", "MFA-SVR", "mfa")
 | 
					            SubSystemServer("MFServer", "MFA-SVR", "mfa")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,46 +11,61 @@
 | 
				
			|||||||
#include "Daemon.h"
 | 
					#include "Daemon.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoGet() {
 | 
					    void RESTAPI_action_links::DoGet() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto Action = GetParameter("action","");
 | 
					        auto Action = GetParameter("action","");
 | 
				
			||||||
        auto Id = GetParameter("id","");
 | 
					        auto Id = GetParameter("id","");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SecurityObjects::ActionLink Link;
 | 
				
			||||||
 | 
					        if(!StorageService()->GetActionLink(Id,Link))
 | 
				
			||||||
 | 
					            return DoReturnA404();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Action=="password_reset")
 | 
					        if(Action=="password_reset")
 | 
				
			||||||
            return RequestResetPassword(Id);
 | 
					            return RequestResetPassword(Link);
 | 
				
			||||||
        else if(Action=="email_verification")
 | 
					        else if(Action=="email_verification")
 | 
				
			||||||
            return DoEmailVerification(Id);
 | 
					            return DoEmailVerification(Link);
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            return DoReturnA404();
 | 
					            return DoReturnA404();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoPost() {
 | 
					    void RESTAPI_action_links::DoPost() {
 | 
				
			||||||
        auto Action = GetParameter("action","");
 | 
					        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")
 | 
					        if(Action=="password_reset")
 | 
				
			||||||
            CompleteResetPassword(Id);
 | 
					            return CompleteResetPassword();
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            DoReturnA404();
 | 
					            return DoReturnA404();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::RequestResetPassword(std::string &Id) {
 | 
					    void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
 | 
				
			||||||
        Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
 | 
					        Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId));
 | 
				
			||||||
        Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
 | 
					        Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
 | 
				
			||||||
        Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
				
			||||||
                                          {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
					                                          {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
				
			||||||
        SendHTMLFileBack(FormFile,FormVars);
 | 
					        SendHTMLFileBack(FormFile,FormVars);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::CompleteResetPassword(std::string &Id) {
 | 
					    void RESTAPI_action_links::CompleteResetPassword() {
 | 
				
			||||||
        //  form has been posted...
 | 
					        //  form has been posted...
 | 
				
			||||||
        RESTAPI_PartHandler PartHandler;
 | 
					        RESTAPI_PartHandler PartHandler;
 | 
				
			||||||
        Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
					        Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
				
			||||||
        if (!Form.empty()) {
 | 
					        if (!Form.empty()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto Password1 = Form.get("password1","bla");
 | 
					            auto Password1 = Form.get("password1","bla");
 | 
				
			||||||
            auto Password2 = Form.get("password1","blu");
 | 
					            auto Password2 = Form.get("password1","blu");
 | 
				
			||||||
            Id = Form.get("id","");
 | 
					            auto Id = Form.get("id","");
 | 
				
			||||||
 | 
					            auto Now = std::time(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            SecurityObjects::ActionLink Link;
 | 
				
			||||||
 | 
					            if(!StorageService()->GetActionLink(Id,Link))
 | 
				
			||||||
 | 
					                return DoReturnA404();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(Now > Link.expires) {
 | 
				
			||||||
 | 
					                StorageService()->CancelAction(Id);
 | 
				
			||||||
 | 
					                return DoReturnA404();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
 | 
					            if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
					                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
				
			||||||
@@ -62,7 +77,7 @@ namespace OpenWifi {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::UserInfo   UInfo;
 | 
					            SecurityObjects::UserInfo   UInfo;
 | 
				
			||||||
            if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
					            if(!StorageService()->GetUserById(Link.userId,UInfo)) {
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
					                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
				
			||||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
					                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
				
			||||||
@@ -82,37 +97,45 @@ namespace OpenWifi {
 | 
				
			|||||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
					                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					                return SendHTMLFileBack(FormFile,FormVars);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            StorageService()->UpdateUserInfo(UInfo.email,Id,UInfo);
 | 
					            StorageService()->UpdateUserInfo(UInfo.email,Link.userId,UInfo);
 | 
				
			||||||
            Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
 | 
					            Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
 | 
				
			||||||
            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
				
			||||||
                                              {"USERNAME", UInfo.email},
 | 
					                                              {"USERNAME", UInfo.email},
 | 
				
			||||||
                                              {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
					                                              {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
				
			||||||
 | 
					            StorageService()->CompleteAction(Id);
 | 
				
			||||||
            SendHTMLFileBack(FormFile,FormVars);
 | 
					            SendHTMLFileBack(FormFile,FormVars);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            DoReturnA404();
 | 
					            DoReturnA404();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoEmailVerification(std::string &Id) {
 | 
					    void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
 | 
				
			||||||
        SecurityObjects::UserInfo UInfo;
 | 
					        auto Now = std::time(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), Id));
 | 
					        if(Now > Link.expires) {
 | 
				
			||||||
        if (!StorageService()->GetUserById(Id, UInfo)) {
 | 
					            StorageService()->CancelAction(Link.id);
 | 
				
			||||||
            Types::StringPairVec FormVars{{"UUID",       Id},
 | 
					            return DoReturnA404();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
 | 
					        if (!StorageService()->GetUserById(Link.userId, UInfo)) {
 | 
				
			||||||
 | 
					            Types::StringPairVec FormVars{{"UUID",       Link.id},
 | 
				
			||||||
                                          {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
 | 
					                                          {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
 | 
				
			||||||
            Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
 | 
					            Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
 | 
				
			||||||
            return SendHTMLFileBack(FormFile, FormVars);
 | 
					            return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email));
 | 
				
			||||||
        UInfo.waitingForEmailCheck = false;
 | 
					        UInfo.waitingForEmailCheck = false;
 | 
				
			||||||
        UInfo.validated = true;
 | 
					        UInfo.validated = true;
 | 
				
			||||||
        UInfo.lastEmailCheck = std::time(nullptr);
 | 
					        UInfo.lastEmailCheck = std::time(nullptr);
 | 
				
			||||||
        UInfo.validationDate = std::time(nullptr);
 | 
					        UInfo.validationDate = std::time(nullptr);
 | 
				
			||||||
        StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo);
 | 
					        StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
        Types::StringPairVec FormVars{{"UUID",     Id},
 | 
					        Types::StringPairVec FormVars{{"UUID",     Link.id},
 | 
				
			||||||
                                      {"USERNAME", UInfo.email},
 | 
					                                      {"USERNAME", UInfo.email},
 | 
				
			||||||
                                      {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
					                                      {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
				
			||||||
        Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
 | 
					        Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
 | 
				
			||||||
 | 
					        StorageService()->CompleteAction(Link.id);
 | 
				
			||||||
        SendHTMLFileBack(FormFile, FormVars);
 | 
					        SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,11 +19,12 @@ namespace OpenWifi {
 | 
				
			|||||||
                                        Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
					                                        Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                        Server,
 | 
					                                        Server,
 | 
				
			||||||
                                        Internal,
 | 
					                                        Internal,
 | 
				
			||||||
                                        false) {}
 | 
					                                        false,
 | 
				
			||||||
 | 
					                                        true, RateLimit{.Interval=1000,.MaxCalls=5}) {}
 | 
				
			||||||
        static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
 | 
					        static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
 | 
				
			||||||
        void RequestResetPassword(std::string &Id);
 | 
					        void RequestResetPassword(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void CompleteResetPassword(std::string &Id);
 | 
					        void CompleteResetPassword();
 | 
				
			||||||
        void DoEmailVerification(std::string &Id);
 | 
					        void DoEmailVerification(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void DoReturnA404();
 | 
					        void DoReturnA404();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void DoGet() final;
 | 
					        void DoGet() final;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,11 +14,12 @@
 | 
				
			|||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
#include "framework/RESTAPI_protocol.h"
 | 
					#include "framework/RESTAPI_protocol.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void RESTAPI_oauth2Handler::DoGet() {
 | 
						void RESTAPI_oauth2Handler::DoGet() {
 | 
				
			||||||
        if (!IsAuthorized()) {
 | 
					        if (!IsAuthorized()) {
 | 
				
			||||||
            return UnAuthorized("Not authorized.");
 | 
					            return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
 | 
					        bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
 | 
				
			||||||
        if(GetMe) {
 | 
					        if(GetMe) {
 | 
				
			||||||
@@ -27,7 +28,7 @@ namespace OpenWifi {
 | 
				
			|||||||
            UserInfo_.userinfo.to_json(Me);
 | 
					            UserInfo_.userinfo.to_json(Me);
 | 
				
			||||||
            return ReturnObject(Me);
 | 
					            return ReturnObject(Me);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        BadRequest("Ill-formed request. Please consult documentation.");
 | 
					        BadRequest(RESTAPI::Errors::UnrecognizedRequest);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_oauth2Handler::DoDelete() {
 | 
					    void RESTAPI_oauth2Handler::DoDelete() {
 | 
				
			||||||
@@ -63,31 +64,46 @@ namespace OpenWifi {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
 | 
					        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
 | 
				
			||||||
            //  Send an email to the userId
 | 
					            SecurityObjects::UserInfo UInfo1;
 | 
				
			||||||
 | 
					            auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1);
 | 
				
			||||||
 | 
					            if(UserExists) {
 | 
				
			||||||
                Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
					                Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
				
			||||||
            SecurityObjects::UserInfoAndPolicy UInfo;
 | 
					                SecurityObjects::ActionLink NewLink;
 | 
				
			||||||
            if(AuthService::SendEmailToUser(userId,AuthService::FORGOT_PASSWORD))
 | 
					
 | 
				
			||||||
                Logger_.information(Poco::format("Send password reset link to %s",userId));
 | 
					                NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
 | 
				
			||||||
            UInfo.webtoken.userMustChangePassword=true;
 | 
					                NewLink.id = MicroService::instance().CreateUUID();
 | 
				
			||||||
 | 
					                NewLink.userId = UInfo1.Id;
 | 
				
			||||||
 | 
					                NewLink.created = std::time(nullptr);
 | 
				
			||||||
 | 
					                NewLink.expires = NewLink.created + (24*60*60);
 | 
				
			||||||
 | 
					                StorageService()->CreateAction(NewLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Poco::JSON::Object ReturnObj;
 | 
					                Poco::JSON::Object ReturnObj;
 | 
				
			||||||
 | 
					                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
 | 
					                UInfo.webtoken.userMustChangePassword = true;
 | 
				
			||||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
					                UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                return ReturnObject(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)) {
 | 
					        if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
 | 
				
			||||||
            Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
					            Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
				
			||||||
            if(Obj->has("uuid")) {
 | 
					            if(Obj->has(RESTAPI::Protocol::UUID)) {
 | 
				
			||||||
                auto uuid = Obj->get("uuid").toString();
 | 
					                auto uuid = Obj->get(RESTAPI::Protocol::UUID).toString();
 | 
				
			||||||
                if(MFAServer().ResendCode(uuid))
 | 
					                if(MFAServer().ResendCode(uuid))
 | 
				
			||||||
                    return OK();
 | 
					                    return OK();
 | 
				
			||||||
                return UnAuthorized("Unrecognized credentials (username/password).");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return UnAuthorized("Unrecognized credentials (username/password).");
 | 
					            return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
 | 
					        if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
 | 
				
			||||||
            Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
					            Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
 | 
				
			||||||
            if(Obj->has("uuid")) {
 | 
					            if(Obj->has(RESTAPI::Protocol::UUID)) {
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
					                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
 | 
					                if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
 | 
				
			||||||
                    Poco::JSON::Object ReturnObj;
 | 
					                    Poco::JSON::Object ReturnObj;
 | 
				
			||||||
@@ -95,29 +111,36 @@ namespace OpenWifi {
 | 
				
			|||||||
                    return ReturnObject(ReturnObj);
 | 
					                    return ReturnObject(ReturnObj);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return UnAuthorized("Unrecognized credentials (username/password).");
 | 
					            return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfoAndPolicy UInfo;
 | 
					        SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
        auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
 | 
					        auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
 | 
				
			||||||
        if (Code==AuthService::SUCCESS) {
 | 
					        if (Code==SUCCESS) {
 | 
				
			||||||
            Poco::JSON::Object ReturnObj;
 | 
					            Poco::JSON::Object ReturnObj;
 | 
				
			||||||
            if(AuthService()->RequiresMFA(UInfo)) {
 | 
					            if(AuthService()->RequiresMFA(UInfo)) {
 | 
				
			||||||
                if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
 | 
					                if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
 | 
				
			||||||
                    return ReturnObject(ReturnObj);
 | 
					                    return ReturnObject(ReturnObj);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now.");
 | 
					                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            UInfo.webtoken.to_json(ReturnObj);
 | 
					            UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
            return ReturnObject(ReturnObj);
 | 
					            return ReturnObject(ReturnObj);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            switch(Code) {
 | 
					            switch(Code) {
 | 
				
			||||||
                case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break;
 | 
					                case INVALID_CREDENTIALS:
 | 
				
			||||||
                case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break;
 | 
					                    return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code);
 | 
				
			||||||
                case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break;
 | 
					                case PASSWORD_INVALID:
 | 
				
			||||||
                case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break;
 | 
					                    return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code);
 | 
				
			||||||
                case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break;
 | 
					                case PASSWORD_ALREADY_USED:
 | 
				
			||||||
                default: return UnAuthorized("Unrecognized credentials (username/password)."); break;
 | 
					                    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;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ namespace OpenWifi {
 | 
				
			|||||||
                                                      Poco::Net::HTTPRequest::HTTP_GET,
 | 
					                                                      Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
													  Server,
 | 
																		  Server,
 | 
				
			||||||
													  Internal, false) {}
 | 
																		  Internal, false, true , RateLimit{.Interval=2000,.MaxCalls=5}) {}
 | 
				
			||||||
		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
 | 
							static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
 | 
				
			||||||
		void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
		void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,11 @@ namespace OpenWifi {
 | 
				
			|||||||
        } else if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
					        } else if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
				
			||||||
            return NotFound();
 | 
					            return NotFound();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  UserInfoObject;
 | 
					        Poco::JSON::Object  UserInfoObject;
 | 
				
			||||||
 | 
					        UInfo.currentPassword.clear();
 | 
				
			||||||
 | 
					        UInfo.lastPasswords.clear();
 | 
				
			||||||
 | 
					        UInfo.oauthType.clear();
 | 
				
			||||||
        UInfo.to_json(UserInfoObject);
 | 
					        UInfo.to_json(UserInfoObject);
 | 
				
			||||||
        ReturnObject(UserInfoObject);
 | 
					        ReturnObject(UserInfoObject);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -36,17 +40,30 @@ namespace OpenWifi {
 | 
				
			|||||||
            return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
					            return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.userRole!= SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
 | 
				
			||||||
 | 
					            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.Id == Id) {
 | 
				
			||||||
 | 
					            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo UInfo;
 | 
					        SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
        if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
					        if(!StorageService()->GetUserById(Id,UInfo)) {
 | 
				
			||||||
            return NotFound();
 | 
					            return NotFound();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UInfo.userRole==SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
					            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
 | 
					        if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
 | 
				
			||||||
            return NotFound();
 | 
					            return NotFound();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(AuthService()->DeleteUserFromCache(UInfo.email))
 | 
					        if(AuthService()->DeleteUserFromCache(UInfo.email)) {
 | 
				
			||||||
            ;
 | 
					            // nothing to do
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
 | 
					        Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
 | 
				
			||||||
        StorageService()->RevokeAllTokens(UInfo.email);
 | 
					        StorageService()->RevokeAllTokens(UInfo.email);
 | 
				
			||||||
        Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
 | 
					        Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
 | 
				
			||||||
@@ -66,6 +83,14 @@ namespace OpenWifi {
 | 
				
			|||||||
            return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
					            return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
 | 
				
			||||||
 | 
					            return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && UInfo.userRole == SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
					            return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(UInfo.email);
 | 
					        Poco::toLowerInPlace(UInfo.email);
 | 
				
			||||||
        if(!Utils::ValidEMailAddress(UInfo.email)) {
 | 
					        if(!Utils::ValidEMailAddress(UInfo.email)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
					            return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
				
			||||||
@@ -115,6 +140,14 @@ namespace OpenWifi {
 | 
				
			|||||||
            return NotFound();
 | 
					            return NotFound();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
 | 
				
			||||||
 | 
					            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole == SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
					            return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo   NewUser;
 | 
					        SecurityObjects::UserInfo   NewUser;
 | 
				
			||||||
        auto RawObject = ParseStream();
 | 
					        auto RawObject = ParseStream();
 | 
				
			||||||
        if(!NewUser.from_json(RawObject)) {
 | 
					        if(!NewUser.from_json(RawObject)) {
 | 
				
			||||||
@@ -136,8 +169,19 @@ namespace OpenWifi {
 | 
				
			|||||||
        AssignIfPresent(RawObject,"suspended", Existing.suspended);
 | 
					        AssignIfPresent(RawObject,"suspended", Existing.suspended);
 | 
				
			||||||
        AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
 | 
					        AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(RawObject->has("userRole"))
 | 
					        if(RawObject->has("userRole")) {
 | 
				
			||||||
            Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
					            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")) {
 | 
					        if(RawObject->has("notes")) {
 | 
				
			||||||
            SecurityObjects::NoteInfoVec NIV;
 | 
					            SecurityObjects::NoteInfoVec NIV;
 | 
				
			||||||
            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
 | 
					            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
 | 
				
			||||||
@@ -161,26 +205,27 @@ namespace OpenWifi {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(RawObject->has("userTypeProprietaryInfo")) {
 | 
					        if(RawObject->has("userTypeProprietaryInfo")) {
 | 
				
			||||||
 | 
					            bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
 | 
					            Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
 | 
				
			||||||
            if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") {
 | 
					
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
 | 
					            auto PropInfo = RawObject->get("userTypeProprietaryInfo");
 | 
				
			||||||
                auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
 | 
					            auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
                auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
 | 
					
 | 
				
			||||||
                if(Info->isArray("mobiles")) {
 | 
					            if(PInfo->isArray("mobiles")) {
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
 | 
					                Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
 | 
					
 | 
				
			||||||
 | 
					            if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
					                return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
 | 
					
 | 
				
			||||||
 | 
					            if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
					                return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            } else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
 | 
					
 | 
				
			||||||
 | 
					            if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
 | 
					                Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
 | 
					 | 
				
			||||||
                    return BadRequest(RESTAPI::Errors::BadMFAMethod);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,11 +16,14 @@ namespace OpenWifi {
 | 
				
			|||||||
            Poco::JSON::Array ArrayObj;
 | 
					            Poco::JSON::Array ArrayObj;
 | 
				
			||||||
            Poco::JSON::Object Answer;
 | 
					            Poco::JSON::Object Answer;
 | 
				
			||||||
            if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
 | 
					            if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
 | 
				
			||||||
                for (const auto &i : Users) {
 | 
					                for (auto &i : Users) {
 | 
				
			||||||
                    Poco::JSON::Object Obj;
 | 
					                    Poco::JSON::Object Obj;
 | 
				
			||||||
                    if (IdOnly) {
 | 
					                    if (IdOnly) {
 | 
				
			||||||
                        ArrayObj.add(i.Id);
 | 
					                        ArrayObj.add(i.Id);
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        i.currentPassword.clear();
 | 
				
			||||||
 | 
					                        i.lastPasswords.clear();
 | 
				
			||||||
 | 
					                        i.oauthType.clear();
 | 
				
			||||||
                        i.to_json(Obj);
 | 
					                        i.to_json(Obj);
 | 
				
			||||||
                        ArrayObj.add(Obj);
 | 
					                        ArrayObj.add(Obj);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -38,6 +41,9 @@ namespace OpenWifi {
 | 
				
			|||||||
                    if (IdOnly) {
 | 
					                    if (IdOnly) {
 | 
				
			||||||
                        ArrayObj.add(UInfo.Id);
 | 
					                        ArrayObj.add(UInfo.Id);
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        UInfo.currentPassword.clear();
 | 
				
			||||||
 | 
					                        UInfo.lastPasswords.clear();
 | 
				
			||||||
 | 
					                        UInfo.oauthType.clear();
 | 
				
			||||||
                        UInfo.to_json(Obj);
 | 
					                        UInfo.to_json(Obj);
 | 
				
			||||||
                        ArrayObj.add(Obj);
 | 
					                        ArrayObj.add(Obj);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,7 +68,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool Device::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool Device::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"serialNumber",SerialNumber);
 | 
								field_from_json(Obj,"serialNumber",SerialNumber);
 | 
				
			||||||
			field_from_json(Obj,"deviceType",DeviceType);
 | 
								field_from_json(Obj,"deviceType",DeviceType);
 | 
				
			||||||
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		field_to_json(Obj,"attachFile", AttachDate);
 | 
							field_to_json(Obj,"attachFile", AttachDate);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"name",Name);
 | 
								field_from_json(Obj,"name",Name);
 | 
				
			||||||
			field_from_json(Obj,"configuration",Configuration);
 | 
								field_from_json(Obj,"configuration",Configuration);
 | 
				
			||||||
@@ -166,7 +166,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		field_to_json(Obj,"created", created);
 | 
							field_to_json(Obj,"created", created);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"serialNumber",serialNumber);
 | 
								field_from_json(Obj,"serialNumber",serialNumber);
 | 
				
			||||||
			field_from_json(Obj,"author",author);
 | 
								field_from_json(Obj,"author",author);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		std::string DevicePassword;
 | 
							std::string DevicePassword;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		void to_json_with_status(Poco::JSON::Object &Obj) const;
 | 
							void to_json_with_status(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
		void Print() const;
 | 
							void Print() const;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,7 +116,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		uint64_t 	Created;
 | 
							uint64_t 	Created;
 | 
				
			||||||
		uint64_t 	LastModified;
 | 
							uint64_t 	LastModified;
 | 
				
			||||||
		void 		to_json(Poco::JSON::Object &Obj) const;
 | 
							void 		to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool 		from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool 		from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct CommandDetails {
 | 
						struct CommandDetails {
 | 
				
			||||||
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		std::string author;
 | 
							std::string author;
 | 
				
			||||||
		uint64_t created;
 | 
							uint64_t created;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct RttySessionDetails {
 | 
						struct RttySessionDetails {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,27 +10,30 @@
 | 
				
			|||||||
#include "RESTAPI_ProvObjects.h"
 | 
					#include "RESTAPI_ProvObjects.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using OpenWifi::RESTAPI_utils::field_to_json;
 | 
				
			||||||
 | 
					using OpenWifi::RESTAPI_utils::field_from_json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::ProvObjects {
 | 
					namespace OpenWifi::ProvObjects {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"id",id);
 | 
					        field_to_json(Obj,"id",id);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"name",name);
 | 
					        field_to_json(Obj,"name",name);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"description",description);
 | 
					        field_to_json(Obj,"description",description);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"created",created);
 | 
					        field_to_json(Obj,"created",created);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"modified",modified);
 | 
					        field_to_json(Obj,"modified",modified);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"notes",notes);
 | 
					        field_to_json(Obj,"notes",notes);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj,"tags",tags);
 | 
					        field_to_json(Obj,"tags",tags);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"id",id);
 | 
					            field_from_json(Obj,"id",id);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"name",name);
 | 
					            field_from_json(Obj,"name",name);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"description",description);
 | 
					            field_from_json(Obj,"description",description);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"created",created);
 | 
					            field_from_json(Obj,"created",created);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"modified",modified);
 | 
					            field_from_json(Obj,"modified",modified);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"notes",notes);
 | 
					            field_from_json(Obj,"notes",notes);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj,"tags",tags);
 | 
					            field_from_json(Obj,"tags",tags);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,18 +42,18 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"users",users);
 | 
					        field_to_json( Obj,"users",users);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"resources",resources);
 | 
					        field_to_json( Obj,"resources",resources);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"access",access);
 | 
					        field_to_json( Obj,"access",access);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"policy",policy);
 | 
					        field_to_json( Obj,"policy",policy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"users",users);
 | 
					            field_from_json( Obj,"users",users);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"resources",resources);
 | 
					            field_from_json( Obj,"resources",resources);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"access",access);
 | 
					            field_from_json( Obj,"access",access);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"policy",policy);
 | 
					            field_from_json( Obj,"policy",policy);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,17 +63,17 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
					        field_to_json(Obj, "entries", entries);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "inUse", inUse);
 | 
					        field_to_json(Obj, "inUse", inUse);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "entity", entity);
 | 
					        field_to_json(Obj, "entity", entity);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj, "entries", entries);
 | 
					            field_from_json(Obj, "entries", entries);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj, "inUse", inUse);
 | 
					            field_from_json(Obj, "inUse", inUse);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj, "entity", entity);
 | 
					            field_from_json(Obj, "entity", entity);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,31 +83,31 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void Entity::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void Entity::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
					        field_to_json( Obj,"parent",parent);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"venues",venues);
 | 
					        field_to_json( Obj,"venues",venues);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"children",children);
 | 
					        field_to_json( Obj,"children",children);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"contacts",contacts);
 | 
					        field_to_json( Obj,"contacts",contacts);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"locations",locations);
 | 
					        field_to_json( Obj,"locations",locations);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"devices",devices);
 | 
					        field_to_json( Obj,"devices",devices);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
					        field_to_json( Obj,"rrm",rrm);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
 | 
					        field_to_json( Obj,"sourceIP",sourceIP);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
					            field_from_json( Obj,"parent",parent);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"venues",venues);
 | 
					            field_from_json( Obj,"venues",venues);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"children",children);
 | 
					            field_from_json( Obj,"children",children);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"contacts",contacts);
 | 
					            field_from_json( Obj,"contacts",contacts);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"locations",locations);
 | 
					            field_from_json( Obj,"locations",locations);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"devices",devices);
 | 
					            field_from_json( Obj,"devices",devices);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
					            field_from_json( Obj,"rrm",rrm);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
 | 
					            field_from_json( Obj,"sourceIP",sourceIP);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,14 +116,14 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
					        field_to_json( Obj,"parent",parent);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"child",child);
 | 
					        field_to_json( Obj,"child",child);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
					            field_from_json( Obj,"parent",parent);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"child",child);
 | 
					            field_from_json( Obj,"child",child);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch (...) {
 | 
					        } catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,37 +133,37 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void Venue::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void Venue::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
					        field_to_json( Obj,"parent",parent);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
					        field_to_json( Obj,"entity",entity);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"children",children);
 | 
					        field_to_json( Obj,"children",children);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"devices",devices);
 | 
					        field_to_json( Obj,"devices",devices);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"topology",topology);
 | 
					        field_to_json( Obj,"topology",topology);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"parent",parent);
 | 
					        field_to_json( Obj,"parent",parent);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"design",design);
 | 
					        field_to_json( Obj,"design",design);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"contact",contact);
 | 
					        field_to_json( Obj,"contact",contact);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"location",location);
 | 
					        field_to_json( Obj,"location",location);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
					        field_to_json( Obj,"rrm",rrm);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
 | 
					        field_to_json( Obj,"sourceIP",sourceIP);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
					            field_from_json( Obj,"parent",parent);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"children",children);
 | 
					            field_from_json( Obj,"children",children);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"devices",devices);
 | 
					            field_from_json( Obj,"devices",devices);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"topology",topology);
 | 
					            field_from_json( Obj,"topology",topology);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"parent",parent);
 | 
					            field_from_json( Obj,"parent",parent);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"design",design);
 | 
					            field_from_json( Obj,"design",design);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"contact",contact);
 | 
					            field_from_json( Obj,"contact",contact);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"location",location);
 | 
					            field_from_json( Obj,"location",location);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
					            field_from_json( Obj,"rrm",rrm);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
 | 
					            field_from_json( Obj,"sourceIP",sourceIP);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch (...) {
 | 
					        } catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,16 +172,16 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"id",id);
 | 
					        field_to_json( Obj,"id",id);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"entity",loginId);
 | 
					        field_to_json( Obj,"entity",loginId);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"children",userType);
 | 
					        field_to_json( Obj,"children",userType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"id",id);
 | 
					            field_from_json( Obj,"id",id);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",loginId);
 | 
					            field_from_json( Obj,"entity",loginId);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"children",userType);
 | 
					            field_from_json( Obj,"children",userType);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -187,17 +190,17 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"users",users);
 | 
					        field_to_json( Obj,"users",users);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
					        field_to_json( Obj,"entity",entity);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"users",users);
 | 
					            field_from_json( Obj,"users",users);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -206,39 +209,39 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void Location::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void Location::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
 | 
					        field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName);
 | 
					        field_to_json( Obj,"buildingName",buildingName);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines);
 | 
					        field_to_json( Obj,"addressLines",addressLines);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"city",city);
 | 
					        field_to_json( Obj,"city",city);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"state",state);
 | 
					        field_to_json( Obj,"state",state);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"postal",postal);
 | 
					        field_to_json( Obj,"postal",postal);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"country",country);
 | 
					        field_to_json( Obj,"country",country);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"phones",phones);
 | 
					        field_to_json( Obj,"phones",phones);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
 | 
					        field_to_json( Obj,"mobiles",mobiles);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode);
 | 
					        field_to_json( Obj,"geoCode",geoCode);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
					        field_to_json( Obj,"inUse",inUse);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
					        field_to_json( Obj,"entity",entity);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            std::string tmp_type;
 | 
					            std::string tmp_type;
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"type", tmp_type);
 | 
					            field_from_json( Obj,"type", tmp_type);
 | 
				
			||||||
            type = location_from_string(tmp_type);
 | 
					            type = location_from_string(tmp_type);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName);
 | 
					            field_from_json( Obj,"buildingName",buildingName);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines);
 | 
					            field_from_json( Obj,"addressLines",addressLines);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"city",city);
 | 
					            field_from_json( Obj,"city",city);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"state",state);
 | 
					            field_from_json( Obj,"state",state);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"postal",postal);
 | 
					            field_from_json( Obj,"postal",postal);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"country",country);
 | 
					            field_from_json( Obj,"country",country);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"phones",phones);
 | 
					            field_from_json( Obj,"phones",phones);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
 | 
					            field_from_json( Obj,"mobiles",mobiles);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
 | 
					            field_from_json( Obj,"geoCode",geoCode);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
					            field_from_json( Obj,"inUse",inUse);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch (...) {
 | 
					        } catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -248,43 +251,43 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void Contact::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void Contact::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"type", to_string(type));
 | 
					        field_to_json( Obj,"type", to_string(type));
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"title",title);
 | 
					        field_to_json( Obj,"title",title);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"salutation",salutation);
 | 
					        field_to_json( Obj,"salutation",salutation);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"firstname",firstname);
 | 
					        field_to_json( Obj,"firstname",firstname);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"lastname",lastname);
 | 
					        field_to_json( Obj,"lastname",lastname);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"initials",initials);
 | 
					        field_to_json( Obj,"initials",initials);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"visual",visual);
 | 
					        field_to_json( Obj,"visual",visual);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
 | 
					        field_to_json( Obj,"mobiles",mobiles);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"phones",phones);
 | 
					        field_to_json( Obj,"phones",phones);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail);
 | 
					        field_to_json( Obj,"primaryEmail",primaryEmail);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail);
 | 
					        field_to_json( Obj,"secondaryEmail",secondaryEmail);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN);
 | 
					        field_to_json( Obj,"accessPIN",accessPIN);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
					        field_to_json( Obj,"inUse",inUse);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"entity",entity);
 | 
					        field_to_json( Obj,"entity",entity);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            std::string tmp_type;
 | 
					            std::string tmp_type;
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"type", tmp_type);
 | 
					            field_from_json( Obj,"type", tmp_type);
 | 
				
			||||||
            type = contact_from_string(tmp_type);
 | 
					            type = contact_from_string(tmp_type);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"title",title);
 | 
					            field_from_json( Obj,"title",title);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"salutation",salutation);
 | 
					            field_from_json( Obj,"salutation",salutation);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"firstname",firstname);
 | 
					            field_from_json( Obj,"firstname",firstname);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"lastname",lastname);
 | 
					            field_from_json( Obj,"lastname",lastname);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"initials",initials);
 | 
					            field_from_json( Obj,"initials",initials);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"visual",visual);
 | 
					            field_from_json( Obj,"visual",visual);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
 | 
					            field_from_json( Obj,"mobiles",mobiles);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"phones",phones);
 | 
					            field_from_json( Obj,"phones",phones);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail);
 | 
					            field_from_json( Obj,"primaryEmail",primaryEmail);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail);
 | 
					            field_from_json( Obj,"secondaryEmail",secondaryEmail);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN);
 | 
					            field_from_json( Obj,"accessPIN",accessPIN);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
					            field_from_json( Obj,"inUse",inUse);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch (...) {
 | 
					        } catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -294,35 +297,35 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber);
 | 
					        field_to_json(Obj, "serialNumber", serialNumber);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "venue", venue);
 | 
					        field_to_json(Obj, "venue", venue);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "entity", entity);
 | 
					        field_to_json(Obj, "entity", entity);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber);
 | 
					        field_to_json(Obj, "subscriber", subscriber);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType);
 | 
					        field_to_json(Obj, "deviceType", deviceType);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode);
 | 
					        field_to_json(Obj, "qrCode", qrCode);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode);
 | 
					        field_to_json(Obj, "geoCode", geoCode);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "location", location);
 | 
					        field_to_json(Obj, "location", location);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "contact", contact);
 | 
					        field_to_json(Obj, "contact", contact);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					        field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
					        field_to_json( Obj,"rrm",rrm);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber);
 | 
					            field_from_json( Obj,"serialNumber",serialNumber);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"venue",venue);
 | 
					            field_from_json( Obj,"venue",venue);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entity",entity);
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber);
 | 
					            field_from_json( Obj,"subscriber",subscriber);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType);
 | 
					            field_from_json( Obj,"deviceType",deviceType);
 | 
				
			||||||
            RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode);
 | 
					            field_from_json(Obj, "qrCode", qrCode);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
 | 
					            field_from_json( Obj,"geoCode",geoCode);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"location",location);
 | 
					            field_from_json( Obj,"location",location);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"contact",contact);
 | 
					            field_from_json( Obj,"contact",contact);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
					            field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
					            field_from_json( Obj,"rrm",rrm);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -331,18 +334,18 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"name", name);
 | 
					        field_to_json( Obj,"name", name);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"description", description);
 | 
					        field_to_json( Obj,"description", description);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"weight", weight);
 | 
					        field_to_json( Obj,"weight", weight);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"configuration", configuration);
 | 
					        field_to_json( Obj,"configuration", configuration);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"name",name);
 | 
					            field_from_json( Obj,"name",name);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"description",description);
 | 
					            field_from_json( Obj,"description",description);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"weight",weight);
 | 
					            field_from_json( Obj,"weight",weight);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
 | 
					            field_from_json( Obj,"configuration",configuration);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -352,27 +355,27 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        info.to_json(Obj);
 | 
					        info.to_json(Obj);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
					        field_to_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes);
 | 
					        field_to_json( Obj,"deviceTypes",deviceTypes);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"configuration",configuration);
 | 
					        field_to_json( Obj,"configuration",configuration);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
 | 
					        field_to_json( Obj,"inUse",inUse);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"variables",variables);
 | 
					        field_to_json( Obj,"variables",variables);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
 | 
					        field_to_json( Obj,"rrm",rrm);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
					        field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
				
			||||||
        RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
					        field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            info.from_json(Obj);
 | 
					            info.from_json(Obj);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
					            field_from_json( Obj,"managementPolicy",managementPolicy);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes);
 | 
					            field_from_json( Obj,"deviceTypes",deviceTypes);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
 | 
					            field_from_json( Obj,"configuration",configuration);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
 | 
					            field_from_json( Obj,"inUse",inUse);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"variables",variables);
 | 
					            field_from_json( Obj,"variables",variables);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
 | 
					            field_from_json( Obj,"rrm",rrm);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
					            field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
					            field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -381,8 +384,8 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Report::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void Report::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot);
 | 
					        field_to_json(Obj, "snapshot", snapShot);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "devices", tenants);
 | 
					        field_to_json(Obj, "devices", tenants);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Report::reset() {
 | 
					    void Report::reset() {
 | 
				
			||||||
@@ -390,16 +393,16 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "uuid", uuid);
 | 
					        field_to_json(Obj, "uuid", uuid);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "name", name);
 | 
					        field_to_json(Obj, "name", name);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "description", description);
 | 
					        field_to_json(Obj, "description", description);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"uuid",uuid);
 | 
					            field_from_json( Obj,"uuid",uuid);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"name",name);
 | 
					            field_from_json( Obj,"name",name);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"description",description);
 | 
					            field_from_json( Obj,"description",description);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -408,14 +411,14 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "type", type);
 | 
					        field_to_json(Obj, "type", type);
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
					        field_to_json(Obj, "entries", entries);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"type",type);
 | 
					            field_from_json( Obj,"type",type);
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entries",entries);
 | 
					            field_from_json( Obj,"entries",entries);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -424,12 +427,94 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const {
 | 
					    void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
        RESTAPI_utils::field_to_json(Obj, "entries", entries);
 | 
					        field_to_json(Obj, "entries", entries);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
					    bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            RESTAPI_utils::field_from_json( Obj,"entries",entries);
 | 
					            field_from_json( Obj,"entries",entries);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void UserList::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
 | 
					        field_to_json(Obj, "list", list);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool UserList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            field_from_json(Obj, "list", list);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void ObjectACL::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
 | 
					        field_to_json(Obj, "users", users);
 | 
				
			||||||
 | 
					        field_to_json(Obj, "access", access);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            field_from_json(Obj, "users", users);
 | 
				
			||||||
 | 
					            field_from_json(Obj, "access", access);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void ObjectACLList::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
 | 
					        field_to_json(Obj, "list", list);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            field_from_json(Obj, "list", list);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Map::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
 | 
					        info.to_json(Obj);
 | 
				
			||||||
 | 
					        field_to_json( Obj,"data",data);
 | 
				
			||||||
 | 
					        field_to_json( Obj,"entity",entity);
 | 
				
			||||||
 | 
					        field_to_json( Obj,"creator",creator);
 | 
				
			||||||
 | 
					        field_to_json( Obj,"visibility",visibility);
 | 
				
			||||||
 | 
					        field_to_json( Obj,"access",access);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            info.from_json(Obj);
 | 
				
			||||||
 | 
					            field_from_json( Obj,"data",data);
 | 
				
			||||||
 | 
					            field_from_json( Obj,"entity",entity);
 | 
				
			||||||
 | 
					            field_from_json( Obj,"creator",creator);
 | 
				
			||||||
 | 
					            field_from_json( Obj,"visibility",visibility);
 | 
				
			||||||
 | 
					            field_from_json( Obj,"access",access);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MapList::to_json(Poco::JSON::Object &Obj) const {
 | 
				
			||||||
 | 
					        field_to_json( Obj,"list",list);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            field_from_json( Obj,"list",list);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch(...) {
 | 
					        } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -438,13 +523,47 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
 | 
					    bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
 | 
				
			||||||
 | 
					        uint64_t Now = std::time(nullptr);
 | 
				
			||||||
        if(O->has("name"))
 | 
					        if(O->has("name"))
 | 
				
			||||||
            I.name = O->get("name").toString();
 | 
					            I.name = O->get("name").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(I.name.empty())
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       if(O->has("description"))
 | 
					       if(O->has("description"))
 | 
				
			||||||
            I.description = O->get("description").toString();
 | 
					            I.description = O->get("description").toString();
 | 
				
			||||||
        SecurityObjects::MergeNotes(O,U,I.notes);
 | 
					        SecurityObjects::MergeNotes(O,U,I.notes);
 | 
				
			||||||
        I.modified = std::time(nullptr);
 | 
					        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;
 | 
				
			||||||
        return true;
 | 
					        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::instance().CreateUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::ProvObjects {
 | 
					namespace OpenWifi::ProvObjects {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum FIRMWARE_UPGRADE_RULES {
 | 
				
			||||||
 | 
					        dont_upgrade,
 | 
				
			||||||
 | 
					        upgrade_inherit,
 | 
				
			||||||
 | 
					        upgrade_release_only,
 | 
				
			||||||
 | 
					        upgrade_latest
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct ObjectInfo {
 | 
					    struct ObjectInfo {
 | 
				
			||||||
        Types::UUID_t   id;
 | 
					        Types::UUID_t   id;
 | 
				
			||||||
        std::string     name;
 | 
					        std::string     name;
 | 
				
			||||||
@@ -317,7 +324,50 @@ namespace OpenWifi::ProvObjects {
 | 
				
			|||||||
        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
					        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct UserList {
 | 
				
			||||||
 | 
					        std::vector<std::string>    list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
 | 
					        bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct ObjectACL {
 | 
				
			||||||
 | 
					        UserList        users;
 | 
				
			||||||
 | 
					        std::string     access;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Map {
 | 
				
			||||||
 | 
					        ObjectInfo          info;
 | 
				
			||||||
 | 
					        std::string         data;
 | 
				
			||||||
 | 
					        std::string         entity;
 | 
				
			||||||
 | 
					        std::string         creator;
 | 
				
			||||||
 | 
					        std::string         visibility;
 | 
				
			||||||
 | 
					        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 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,7 +138,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    field_to_json(Obj,"primary", primary);
 | 
						    field_to_json(Obj,"primary", primary);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
	    try {
 | 
						    try {
 | 
				
			||||||
	        field_from_json(Obj,"number",number);
 | 
						        field_from_json(Obj,"number",number);
 | 
				
			||||||
	        field_from_json(Obj,"verified",verified);
 | 
						        field_from_json(Obj,"verified",verified);
 | 
				
			||||||
@@ -155,7 +155,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    field_to_json(Obj,"method", method);
 | 
						    field_to_json(Obj,"method", method);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
	    try {
 | 
						    try {
 | 
				
			||||||
	        field_from_json(Obj,"enabled",enabled);
 | 
						        field_from_json(Obj,"enabled",enabled);
 | 
				
			||||||
	        field_from_json(Obj,"method",method);
 | 
						        field_from_json(Obj,"method",method);
 | 
				
			||||||
@@ -171,7 +171,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    field_to_json(Obj, "mfa", mfa);
 | 
						    field_to_json(Obj, "mfa", mfa);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
	    try {
 | 
						    try {
 | 
				
			||||||
	        field_from_json(Obj,"mobiles",mobiles);
 | 
						        field_from_json(Obj,"mobiles",mobiles);
 | 
				
			||||||
	        field_from_json(Obj,"mfa",mfa);
 | 
						        field_from_json(Obj,"mfa",mfa);
 | 
				
			||||||
@@ -189,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
        field_to_json(Obj, "method", method);
 | 
					        field_to_json(Obj, "method", method);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
					    bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
	    try {
 | 
						    try {
 | 
				
			||||||
	        field_from_json(Obj,"uuid",uuid);
 | 
						        field_from_json(Obj,"uuid",uuid);
 | 
				
			||||||
	        field_from_json(Obj,"question",question);
 | 
						        field_from_json(Obj,"question",question);
 | 
				
			||||||
@@ -208,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 {
 | 
					        try {
 | 
				
			||||||
            field_from_json(Obj,"uuid",uuid);
 | 
					            field_from_json(Obj,"uuid",uuid);
 | 
				
			||||||
            field_from_json(Obj,"answer",answer);
 | 
					            field_from_json(Obj,"answer",answer);
 | 
				
			||||||
@@ -387,11 +387,12 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		field_to_json(Obj,"note", note);
 | 
							field_to_json(Obj,"note", note);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"created",created);
 | 
								field_from_json(Obj,"created",created);
 | 
				
			||||||
			field_from_json(Obj,"createdBy",createdBy);
 | 
								field_from_json(Obj,"createdBy",createdBy);
 | 
				
			||||||
			field_from_json(Obj,"note",note);
 | 
								field_from_json(Obj,"note",note);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
		} catch(...) {
 | 
							} catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -428,10 +429,11 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
 | 
							field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"resource",resource);
 | 
								field_from_json(Obj,"resource",resource);
 | 
				
			||||||
			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
 | 
								field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
		} catch(...) {
 | 
							} catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -447,7 +449,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		field_to_json(Obj,"notes", notes);
 | 
							field_to_json(Obj,"notes", notes);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"id",id);
 | 
								field_from_json(Obj,"id",id);
 | 
				
			||||||
			field_from_json(Obj,"name",name);
 | 
								field_from_json(Obj,"name",name);
 | 
				
			||||||
@@ -455,6 +457,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
			field_from_json(Obj,"policy",policy);
 | 
								field_from_json(Obj,"policy",policy);
 | 
				
			||||||
			field_from_json(Obj,"role",role);
 | 
								field_from_json(Obj,"role",role);
 | 
				
			||||||
			field_from_json(Obj,"notes",notes);
 | 
								field_from_json(Obj,"notes",notes);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
		} catch(...) {
 | 
							} catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -465,9 +468,47 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		field_to_json(Obj, "profiles", profiles);
 | 
							field_to_json(Obj, "profiles", profiles);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) {
 | 
						bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			field_from_json(Obj,"profiles",profiles);
 | 
								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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
						        return true;
 | 
				
			||||||
	    } catch(...) {
 | 
						    } catch(...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
 | 
					#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
#include "../framework/OpenWifiTypes.h"
 | 
					#include "framework/OpenWifiTypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::SecurityObjects {
 | 
					namespace OpenWifi::SecurityObjects {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,7 +53,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		std::string createdBy;
 | 
							std::string createdBy;
 | 
				
			||||||
		std::string note;
 | 
							std::string note;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	typedef std::vector<NoteInfo>	NoteInfoVec;
 | 
						typedef std::vector<NoteInfo>	NoteInfoVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,7 +63,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    bool primary;
 | 
						    bool primary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
						    void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
						    bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct MfaAuthInfo {
 | 
						struct MfaAuthInfo {
 | 
				
			||||||
@@ -71,7 +71,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    std::string method;
 | 
						    std::string method;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
						    void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
						    bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct UserLoginLoginExtensions {
 | 
						struct UserLoginLoginExtensions {
 | 
				
			||||||
@@ -79,7 +79,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    struct MfaAuthInfo mfa;
 | 
						    struct MfaAuthInfo mfa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
						    void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
						    bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct MFAChallengeRequest {
 | 
						struct MFAChallengeRequest {
 | 
				
			||||||
@@ -89,7 +89,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
	    uint64_t    created;
 | 
						    uint64_t    created;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    void to_json(Poco::JSON::Object &Obj) const;
 | 
						    void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
	    bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
						    bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct MFAChallengeResponse {
 | 
					    struct MFAChallengeResponse {
 | 
				
			||||||
@@ -97,7 +97,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
        std::string answer;
 | 
					        std::string answer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void to_json(Poco::JSON::Object &Obj) const;
 | 
					        void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
        bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
					        bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct UserInfo {
 | 
						struct UserInfo {
 | 
				
			||||||
@@ -200,7 +200,7 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		std::string resource;
 | 
							std::string resource;
 | 
				
			||||||
		ResourceAccessType access;
 | 
							ResourceAccessType access;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	typedef std::vector<ProfileAction>	ProfileActionVec;
 | 
						typedef std::vector<ProfileAction>	ProfileActionVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,14 +212,37 @@ namespace OpenWifi::SecurityObjects {
 | 
				
			|||||||
		std::string role;
 | 
							std::string role;
 | 
				
			||||||
		NoteInfoVec notes;
 | 
							NoteInfoVec notes;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	typedef std::vector<SecurityProfile> SecurityProfileVec;
 | 
						typedef std::vector<SecurityProfile> SecurityProfileVec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct SecurityProfileList {
 | 
						struct SecurityProfileList {
 | 
				
			||||||
		SecurityProfileVec profiles;
 | 
							SecurityProfileVec profiles;
 | 
				
			||||||
		void to_json(Poco::JSON::Object &Obj) const;
 | 
							void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
		bool from_json(Poco::JSON::Object::Ptr Obj);
 | 
							bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum LinkActions {
 | 
				
			||||||
 | 
						    FORGOT_PASSWORD=1,
 | 
				
			||||||
 | 
						    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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void to_json(Poco::JSON::Object &Obj) const;
 | 
				
			||||||
 | 
						    bool from_json(Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@
 | 
				
			|||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class SMSSender * SMSSender::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int SMSSender::Start() {
 | 
					    int SMSSender::Start() {
 | 
				
			||||||
        Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");
 | 
					        Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,10 +25,8 @@ namespace OpenWifi {
 | 
				
			|||||||
    class SMSSender : public SubSystemServer {
 | 
					    class SMSSender : public SubSystemServer {
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
            static SMSSender *instance() {
 | 
					            static SMSSender *instance() {
 | 
				
			||||||
                if (instance_ == nullptr) {
 | 
					                static SMSSender instance;
 | 
				
			||||||
                    instance_ = new SMSSender;
 | 
					                return &instance;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return instance_;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int  Start() final;
 | 
					            int  Start() final;
 | 
				
			||||||
@@ -39,7 +37,6 @@ namespace OpenWifi {
 | 
				
			|||||||
            bool IsNumberValid(const std::string &Number, const std::string &UserName);
 | 
					            bool IsNumberValid(const std::string &Number, const std::string &UserName);
 | 
				
			||||||
            [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
 | 
					            [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
 | 
				
			||||||
        private:
 | 
					        private:
 | 
				
			||||||
            static SMSSender * instance_;
 | 
					 | 
				
			||||||
            std::string         Provider_;
 | 
					            std::string         Provider_;
 | 
				
			||||||
            bool                Enabled_=false;
 | 
					            bool                Enabled_=false;
 | 
				
			||||||
            std::vector<SMSValidationCacheEntry>    Cache_;
 | 
					            std::vector<SMSValidationCacheEntry>    Cache_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,11 +18,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "AuthService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class SMTPMailerService * SMTPMailerService::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void SMTPMailerService::LoadMyConfig() {
 | 
					    void SMTPMailerService::LoadMyConfig() {
 | 
				
			||||||
        MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
 | 
					        MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
 | 
				
			||||||
        SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
 | 
					        SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
 | 
				
			||||||
@@ -147,7 +146,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            auto Logo = Msg.Attrs.find(LOGO);
 | 
					            auto Logo = Msg.Attrs.find(LOGO);
 | 
				
			||||||
            if(Logo!=Msg.Attrs.end()) {
 | 
					            if(Logo!=Msg.Attrs.end()) {
 | 
				
			||||||
                Poco::File  LogoFile(TemplateDir_ + "/" + Logo->second);
 | 
					                Poco::File  LogoFile(AuthService::GetLogoAssetFileName());
 | 
				
			||||||
                std::ifstream   IF(LogoFile.path());
 | 
					                std::ifstream   IF(LogoFile.path());
 | 
				
			||||||
                std::ostringstream   OS;
 | 
					                std::ostringstream   OS;
 | 
				
			||||||
                Poco::StreamCopier::copyStream(IF, OS);
 | 
					                Poco::StreamCopier::copyStream(IF, OS);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,10 +59,8 @@ namespace OpenWifi {
 | 
				
			|||||||
    class SMTPMailerService : public SubSystemServer, Poco::Runnable {
 | 
					    class SMTPMailerService : public SubSystemServer, Poco::Runnable {
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
           static SMTPMailerService *instance() {
 | 
					           static SMTPMailerService *instance() {
 | 
				
			||||||
                if (instance_ == nullptr) {
 | 
					               static SMTPMailerService     instance;
 | 
				
			||||||
                    instance_ = new SMTPMailerService;
 | 
					               return & instance;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return instance_;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            struct MessageEvent {
 | 
					            struct MessageEvent {
 | 
				
			||||||
@@ -88,7 +86,6 @@ namespace OpenWifi {
 | 
				
			|||||||
            void reinitialize(Poco::Util::Application &self) override;
 | 
					            void reinitialize(Poco::Util::Application &self) override;
 | 
				
			||||||
            bool Enabled() const { return Enabled_; }
 | 
					            bool Enabled() const { return Enabled_; }
 | 
				
			||||||
        private:
 | 
					        private:
 | 
				
			||||||
            static SMTPMailerService * instance_;
 | 
					 | 
				
			||||||
            std::string             MailHost_;
 | 
					            std::string             MailHost_;
 | 
				
			||||||
            std::string             Sender_;
 | 
					            std::string             Sender_;
 | 
				
			||||||
            int                     MailHostPort_=25;
 | 
					            int                     MailHostPort_=25;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,13 +10,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Storage *Storage::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int Storage::Start() {
 | 
					    int Storage::Start() {
 | 
				
			||||||
		std::lock_guard		Guard(Mutex_);
 | 
							std::lock_guard		Guard(Mutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		StorageClass::Start();
 | 
							StorageClass::Start();
 | 
				
			||||||
		Create_Tables();
 | 
							Create_Tables();
 | 
				
			||||||
 | 
							InitializeDefaultUser();
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,34 +15,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const std::string AllActionLinksFieldsForSelect {
 | 
					 | 
				
			||||||
            "Id, "
 | 
					 | 
				
			||||||
            "Action,"
 | 
					 | 
				
			||||||
            "UserId,"
 | 
					 | 
				
			||||||
            "template,"
 | 
					 | 
				
			||||||
            "locale,"
 | 
					 | 
				
			||||||
            "message,"
 | 
					 | 
				
			||||||
            "sent,"
 | 
					 | 
				
			||||||
            "created,"
 | 
					 | 
				
			||||||
            "expires,"
 | 
					 | 
				
			||||||
            "completed,"
 | 
					 | 
				
			||||||
            "canceled"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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 AllEmailTemplatesFieldsForCreation {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -90,7 +62,7 @@ namespace OpenWifi {
 | 
				
			|||||||
            return UNKNOWN;
 | 
					            return UNKNOWN;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static const std::string from_userType(USER_TYPE U) {
 | 
					        static std::string from_userType(USER_TYPE U) {
 | 
				
			||||||
            switch(U) {
 | 
					            switch(U) {
 | 
				
			||||||
                case ROOT: return "root";
 | 
					                case ROOT: return "root";
 | 
				
			||||||
                case ADMIN: return "admin";
 | 
					                case ADMIN: return "admin";
 | 
				
			||||||
@@ -104,10 +76,8 @@ namespace OpenWifi {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static Storage *instance() {
 | 
					        static Storage *instance() {
 | 
				
			||||||
            if (instance_ == nullptr) {
 | 
					            static Storage instance;
 | 
				
			||||||
                instance_ = new Storage;
 | 
					            return &instance;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return instance_;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int 	Start() override;
 | 
					        int 	Start() override;
 | 
				
			||||||
@@ -116,7 +86,8 @@ namespace OpenWifi {
 | 
				
			|||||||
        /*
 | 
					        /*
 | 
				
			||||||
         *  All user management functions
 | 
					         *  All user management functions
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser);
 | 
					        bool InitializeDefaultUser();
 | 
				
			||||||
 | 
					        bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false);
 | 
				
			||||||
        bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
 | 
					        bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
 | 
				
			||||||
        bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
 | 
					        bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
 | 
				
			||||||
        bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
 | 
					        bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
 | 
				
			||||||
@@ -143,18 +114,20 @@ namespace OpenWifi {
 | 
				
			|||||||
        /*
 | 
					        /*
 | 
				
			||||||
         *  All ActionLinks functions
 | 
					         *  All ActionLinks functions
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements );
 | 
					        bool CreateAction( SecurityObjects::ActionLink & A);
 | 
				
			||||||
        bool DeleteAction(std::string &ActionId);
 | 
					        bool DeleteAction(std::string &ActionId);
 | 
				
			||||||
        bool CompleteAction(std::string &ActionId);
 | 
					        bool CompleteAction(std::string &ActionId);
 | 
				
			||||||
        bool CancelAction(std::string &ActionId);
 | 
					        bool CancelAction(std::string &ActionId);
 | 
				
			||||||
 | 
					        bool SentAction(std::string &ActionId);
 | 
				
			||||||
 | 
					        bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A);
 | 
				
			||||||
 | 
					        bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		static Storage      							*instance_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int Create_Tables();
 | 
					        int Create_Tables();
 | 
				
			||||||
        int Create_UserTable();
 | 
					        int Create_UserTable();
 | 
				
			||||||
        int Create_AvatarTable();
 | 
					        int Create_AvatarTable();
 | 
				
			||||||
        int Create_TokensTable();
 | 
					        int Create_TokensTable();
 | 
				
			||||||
 | 
					        int Create_ActionLinkTable();
 | 
				
			||||||
   };
 | 
					   };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline Storage * StorageService() { return Storage::instance(); };
 | 
					    inline Storage * StorageService() { return Storage::instance(); };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,7 @@ using namespace std::chrono_literals;
 | 
				
			|||||||
#include "Poco/URI.h"
 | 
					#include "Poco/URI.h"
 | 
				
			||||||
#include "Poco/Net/HTTPSClientSession.h"
 | 
					#include "Poco/Net/HTTPSClientSession.h"
 | 
				
			||||||
#include "Poco/Net/NetworkInterface.h"
 | 
					#include "Poco/Net/NetworkInterface.h"
 | 
				
			||||||
 | 
					#include "Poco/ExpireLRUCache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cppkafka/cppkafka.h"
 | 
					#include "cppkafka/cppkafka.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,6 +67,86 @@ using namespace std::chrono_literals;
 | 
				
			|||||||
#include "framework/RESTAPI_errors.h"
 | 
					#include "framework/RESTAPI_errors.h"
 | 
				
			||||||
#include "framework/uCentral_Protocol.h"
 | 
					#include "framework/uCentral_Protocol.h"
 | 
				
			||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					#include "nlohmann/json.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum UNAUTHORIZED_REASON {
 | 
				
			||||||
 | 
					        SUCCESS=0,
 | 
				
			||||||
 | 
					        PASSWORD_CHANGE_REQUIRED,
 | 
				
			||||||
 | 
					        INVALID_CREDENTIALS,
 | 
				
			||||||
 | 
					        PASSWORD_ALREADY_USED,
 | 
				
			||||||
 | 
					        USERNAME_PENDING_VERIFICATION,
 | 
				
			||||||
 | 
					        PASSWORD_INVALID,
 | 
				
			||||||
 | 
					        INTERNAL_ERROR,
 | 
				
			||||||
 | 
					        ACCESS_DENIED,
 | 
				
			||||||
 | 
					        INVALID_TOKEN
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class AppServiceRegistry {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							inline AppServiceRegistry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static AppServiceRegistry & instance() {
 | 
				
			||||||
 | 
								static AppServiceRegistry instance;
 | 
				
			||||||
 | 
								return instance;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline ~AppServiceRegistry() {
 | 
				
			||||||
 | 
								Save();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void Save() {
 | 
				
			||||||
 | 
								std::istringstream  IS( to_string(Registry_));
 | 
				
			||||||
 | 
								std::ofstream       OF;
 | 
				
			||||||
 | 
								OF.open(FileName,std::ios::binary | std::ios::trunc);
 | 
				
			||||||
 | 
								Poco::StreamCopier::copyStream(IS, OF);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void Set(const char *Key, uint64_t Value ) {
 | 
				
			||||||
 | 
								Registry_[Key] = Value;
 | 
				
			||||||
 | 
								Save();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void Set(const char *Key, const std::string &Value ) {
 | 
				
			||||||
 | 
								Registry_[Key] = Value;
 | 
				
			||||||
 | 
								Save();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void Set(const char *Key, bool Value ) {
 | 
				
			||||||
 | 
								Registry_[Key] = Value;
 | 
				
			||||||
 | 
								Save();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool Get(const char *Key, bool & Value ) {
 | 
				
			||||||
 | 
								if(Registry_[Key].is_boolean()) {
 | 
				
			||||||
 | 
									Value = Registry_[Key].get<bool>();
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool Get(const char *Key, uint64_t & Value ) {
 | 
				
			||||||
 | 
								if(Registry_[Key].is_number_unsigned()) {
 | 
				
			||||||
 | 
									Value = Registry_[Key].get<uint64_t>();
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool Get(const char *Key, std::string & Value ) {
 | 
				
			||||||
 | 
								if(Registry_[Key].is_string()) {
 | 
				
			||||||
 | 
									Value = Registry_[Key].get<std::string>();
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							std::string         FileName;
 | 
				
			||||||
 | 
							nlohmann::json      Registry_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::RESTAPI_utils {
 | 
					namespace OpenWifi::RESTAPI_utils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -263,6 +344,21 @@ namespace OpenWifi::RESTAPI_utils {
 | 
				
			|||||||
        return OS.str();
 | 
					        return OS.str();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline std::string to_string(const Types::StringPairVec & ObjectArray) {
 | 
				
			||||||
 | 
					        Poco::JSON::Array OutputArr;
 | 
				
			||||||
 | 
					        if(ObjectArray.empty())
 | 
				
			||||||
 | 
					            return "[]";
 | 
				
			||||||
 | 
					        for(auto const &i:ObjectArray) {
 | 
				
			||||||
 | 
					            Poco::JSON::Array InnerArray;
 | 
				
			||||||
 | 
					            InnerArray.add(i.first);
 | 
				
			||||||
 | 
					            InnerArray.add(i.second);
 | 
				
			||||||
 | 
					            OutputArr.add(InnerArray);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::ostringstream OS;
 | 
				
			||||||
 | 
					        Poco::JSON::Stringifier::condense(OutputArr,OS);
 | 
				
			||||||
 | 
					        return OS.str();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template<class T> std::string to_string(const std::vector<T> & ObjectArray) {
 | 
					    template<class T> std::string to_string(const std::vector<T> & ObjectArray) {
 | 
				
			||||||
        Poco::JSON::Array OutputArr;
 | 
					        Poco::JSON::Array OutputArr;
 | 
				
			||||||
        if(ObjectArray.empty())
 | 
					        if(ObjectArray.empty())
 | 
				
			||||||
@@ -345,6 +441,27 @@ namespace OpenWifi::RESTAPI_utils {
 | 
				
			|||||||
        return Result;
 | 
					        return Result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline Types::StringPairVec to_stringpair_array(const std::string &S) {
 | 
				
			||||||
 | 
					        Types::StringPairVec   R;
 | 
				
			||||||
 | 
					        if(S.empty())
 | 
				
			||||||
 | 
					            return R;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::JSON::Parser P;
 | 
				
			||||||
 | 
					            auto Object = P.parse(S).template extract<Poco::JSON::Array::Ptr>();
 | 
				
			||||||
 | 
					            for (auto const &i : *Object) {
 | 
				
			||||||
 | 
					                auto InnerObject = i.template extract<Poco::JSON::Array::Ptr>();
 | 
				
			||||||
 | 
					                if(InnerObject->size()==2) {
 | 
				
			||||||
 | 
					                    Types::StringPair P{InnerObject->get(0).toString(), InnerObject->get(1).toString()};
 | 
				
			||||||
 | 
					                    R.push_back(P);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return R;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template<class T> std::vector<T> to_object_array(const std::string & ObjectString) {
 | 
					    template<class T> std::vector<T> to_object_array(const std::string & ObjectString) {
 | 
				
			||||||
        std::vector<T>	Result;
 | 
					        std::vector<T>	Result;
 | 
				
			||||||
        if(ObjectString.empty())
 | 
					        if(ObjectString.empty())
 | 
				
			||||||
@@ -729,16 +846,13 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
        return Result;
 | 
					        return Result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline void SaveSystemId(uint64_t Id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [[nodiscard]] inline uint64_t InitializeSystemId() {
 | 
					    [[nodiscard]] inline uint64_t InitializeSystemId() {
 | 
				
			||||||
        std::random_device	RDev;
 | 
					        std::random_device	RDev;
 | 
				
			||||||
        std::srand(RDev());
 | 
					        std::srand(RDev());
 | 
				
			||||||
        std::chrono::high_resolution_clock	Clock;
 | 
					        std::chrono::high_resolution_clock	Clock;
 | 
				
			||||||
        auto Now = Clock.now().time_since_epoch().count();
 | 
					        auto Now = Clock.now().time_since_epoch().count();
 | 
				
			||||||
        auto S = (GetDefaultMacAsInt64() + std::rand() + Now)  ;
 | 
					        auto S = (GetDefaultMacAsInt64() + std::rand() + Now)  ;
 | 
				
			||||||
        SaveSystemId(S);
 | 
							OpenWifi::AppServiceRegistry().Set("systemid",S);
 | 
				
			||||||
        std::cout << "ID: " << S << std::endl;
 | 
					 | 
				
			||||||
        return S;
 | 
					        return S;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -887,6 +1001,7 @@ namespace OpenWifi {
 | 
				
			|||||||
    static const std::string uSERVICE_SUBCRIBER{ "owsub"};
 | 
					    static const std::string uSERVICE_SUBCRIBER{ "owsub"};
 | 
				
			||||||
    static const std::string uSERVICE_INSTALLER{ "owinst"};
 | 
					    static const std::string uSERVICE_INSTALLER{ "owinst"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class MyErrorHandler : public Poco::ErrorHandler {
 | 
						class MyErrorHandler : public Poco::ErrorHandler {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {}
 | 
							explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {}
 | 
				
			||||||
@@ -1309,6 +1424,63 @@ namespace OpenWifi {
 | 
				
			|||||||
	            std::string _fileName;
 | 
						            std::string _fileName;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class RESTAPI_RateLimiter : public SubSystemServer {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    struct ClientCacheEntry {
 | 
				
			||||||
 | 
						        int64_t  Start=0;
 | 
				
			||||||
 | 
						        int      Count=0;
 | 
				
			||||||
 | 
						    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    static RESTAPI_RateLimiter *instance() {
 | 
				
			||||||
 | 
						        static RESTAPI_RateLimiter instance;
 | 
				
			||||||
 | 
						        return &instance;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    inline int Start() final { return 0;};
 | 
				
			||||||
 | 
						    inline void Stop() final { };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    inline bool IsRateLimited(const Poco::Net::HTTPServerRequest &R, int64_t Period, int64_t MaxCalls) {
 | 
				
			||||||
 | 
						        Poco::URI   uri(R.getURI());
 | 
				
			||||||
 | 
						        auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
 | 
				
			||||||
 | 
						        auto E = Cache_.get(H);
 | 
				
			||||||
 | 
						        const auto p1 = std::chrono::system_clock::now();
 | 
				
			||||||
 | 
						        auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(p1.time_since_epoch()).count();
 | 
				
			||||||
 | 
						        if(E.isNull()) {
 | 
				
			||||||
 | 
						            Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
 | 
				
			||||||
 | 
						            Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
 | 
				
			||||||
 | 
						            return false;
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
						        if((Now-E->Start)<Period) {
 | 
				
			||||||
 | 
						            E->Count++;
 | 
				
			||||||
 | 
						            Cache_.update(H,E);
 | 
				
			||||||
 | 
						            if(E->Count > MaxCalls)
 | 
				
			||||||
 | 
						                return true;
 | 
				
			||||||
 | 
						            return false;
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
						        E->Start = Now;
 | 
				
			||||||
 | 
						        E->Count = 1;
 | 
				
			||||||
 | 
						        Cache_.update(H,E);
 | 
				
			||||||
 | 
						        return false;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    inline void Clear() {
 | 
				
			||||||
 | 
						        Cache_.clear();
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
						    Poco::ExpireLRUCache<uint64_t,ClientCacheEntry>      Cache_{2048};
 | 
				
			||||||
 | 
						    std::hash<std::string>          str_hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    RESTAPI_RateLimiter() noexcept:
 | 
				
			||||||
 | 
						    SubSystemServer("RateLimiter", "RATE-LIMITER", "rate.limiter")
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline RESTAPI_RateLimiter * RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
 | 
						class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
	    struct QueryBlock {
 | 
						    struct QueryBlock {
 | 
				
			||||||
@@ -1318,8 +1490,28 @@ namespace OpenWifi {
 | 
				
			|||||||
	    };
 | 
						    };
 | 
				
			||||||
	    typedef std::map<std::string, std::string> BindingMap;
 | 
						    typedef std::map<std::string, std::string> BindingMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods, RESTAPI_GenericServer & Server, bool Internal=false, bool AlwaysAuthorize=true)
 | 
						    struct RateLimit {
 | 
				
			||||||
	    : Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Server_(Server), Internal_(Internal), AlwaysAuthorize_(AlwaysAuthorize) {}
 | 
						        int64_t     Interval=1000;
 | 
				
			||||||
 | 
						        int64_t     MaxCalls=10;
 | 
				
			||||||
 | 
						    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    RESTAPIHandler( BindingMap map,
 | 
				
			||||||
 | 
					                        Poco::Logger &l,
 | 
				
			||||||
 | 
					                        std::vector<std::string> Methods,
 | 
				
			||||||
 | 
					                        RESTAPI_GenericServer & Server,
 | 
				
			||||||
 | 
					                        bool Internal=false,
 | 
				
			||||||
 | 
					                        bool AlwaysAuthorize=true,
 | 
				
			||||||
 | 
					                        bool RateLimited=false,
 | 
				
			||||||
 | 
						                    const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100})
 | 
				
			||||||
 | 
						    :   Bindings_(std::move(map)),
 | 
				
			||||||
 | 
						        Logger_(l),
 | 
				
			||||||
 | 
						        Methods_(std::move(Methods)),
 | 
				
			||||||
 | 
						        Server_(Server),
 | 
				
			||||||
 | 
						        Internal_(Internal),
 | 
				
			||||||
 | 
						        AlwaysAuthorize_(AlwaysAuthorize),
 | 
				
			||||||
 | 
						        RateLimited_(RateLimited),
 | 
				
			||||||
 | 
						        MyRates_(Profile){
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) {
 | 
						    inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) {
 | 
				
			||||||
	        return true;
 | 
						        return true;
 | 
				
			||||||
@@ -1331,6 +1523,9 @@ namespace OpenWifi {
 | 
				
			|||||||
	            Request = &RequestIn;
 | 
						            Request = &RequestIn;
 | 
				
			||||||
	            Response = &ResponseIn;
 | 
						            Response = &ResponseIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						            if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls))
 | 
				
			||||||
 | 
						                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	            if (!ContinueProcessing())
 | 
						            if (!ContinueProcessing())
 | 
				
			||||||
	                return;
 | 
						                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1340,7 +1535,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	            std::string Reason;
 | 
						            std::string Reason;
 | 
				
			||||||
	            if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
 | 
						            if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
 | 
				
			||||||
                    UnAuthorized(Reason);
 | 
					                    UnAuthorized(Reason, ACCESS_DENIED);
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
	            }
 | 
						            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1561,10 +1756,10 @@ namespace OpenWifi {
 | 
				
			|||||||
	        Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
 | 
						        Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline void UnAuthorized(const std::string & Reason = "") {
 | 
						    inline void UnAuthorized(const std::string & Reason = "", int Code = INVALID_CREDENTIALS ) {
 | 
				
			||||||
	        PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
 | 
						        PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
 | 
				
			||||||
	        Poco::JSON::Object	ErrorObject;
 | 
						        Poco::JSON::Object	ErrorObject;
 | 
				
			||||||
	        ErrorObject.set("ErrorCode",403);
 | 
						        ErrorObject.set("ErrorCode",Code);
 | 
				
			||||||
	        ErrorObject.set("ErrorDetails",Request->getMethod());
 | 
						        ErrorObject.set("ErrorDetails",Request->getMethod());
 | 
				
			||||||
	        ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
 | 
						        ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
 | 
				
			||||||
	        std::ostream &Answer = Response->send();
 | 
						        std::ostream &Answer = Response->send();
 | 
				
			||||||
@@ -1609,7 +1804,7 @@ namespace OpenWifi {
 | 
				
			|||||||
	        Response->set("Cache-Control", "private");
 | 
						        Response->set("Cache-Control", "private");
 | 
				
			||||||
	        Response->set("Pragma", "private");
 | 
						        Response->set("Pragma", "private");
 | 
				
			||||||
	        Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
 | 
						        Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
 | 
				
			||||||
	        Response->set("Content-Length", std::to_string(File.getSize()));
 | 
						        Response->setContentLength(File.getSize());
 | 
				
			||||||
	        AddCORS();
 | 
						        AddCORS();
 | 
				
			||||||
	        Response->sendFile(File.path(),"application/octet-stream");
 | 
						        Response->sendFile(File.path(),"application/octet-stream");
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
@@ -1647,10 +1842,10 @@ namespace OpenWifi {
 | 
				
			|||||||
                                     const Types::StringPairVec & FormVars) {
 | 
					                                     const Types::StringPairVec & FormVars) {
 | 
				
			||||||
	        Response->set("Pragma", "private");
 | 
						        Response->set("Pragma", "private");
 | 
				
			||||||
	        Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
 | 
						        Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
 | 
				
			||||||
	        Response->set("Content-Length", std::to_string(File.getSize()));
 | 
						        std::string FormContent = Utils::LoadFile(File.path());
 | 
				
			||||||
	        AddCORS();
 | 
					 | 
				
			||||||
	        auto FormContent = Utils::LoadFile(File.path());
 | 
					 | 
				
			||||||
	        Utils::ReplaceVariables(FormContent, FormVars);
 | 
						        Utils::ReplaceVariables(FormContent, FormVars);
 | 
				
			||||||
 | 
						        Response->setContentLength(FormContent.size());
 | 
				
			||||||
 | 
						        AddCORS();
 | 
				
			||||||
	        Response->setChunkedTransferEncoding(true);
 | 
						        Response->setChunkedTransferEncoding(true);
 | 
				
			||||||
	        Response->setContentType("text/html");
 | 
						        Response->setContentType("text/html");
 | 
				
			||||||
	        std::ostream& ostr = Response->send();
 | 
						        std::ostream& ostr = Response->send();
 | 
				
			||||||
@@ -1760,12 +1955,14 @@ namespace OpenWifi {
 | 
				
			|||||||
	        std::vector<std::string> 	Methods_;
 | 
						        std::vector<std::string> 	Methods_;
 | 
				
			||||||
	        QueryBlock					QB_;
 | 
						        QueryBlock					QB_;
 | 
				
			||||||
	        bool                        Internal_=false;
 | 
						        bool                        Internal_=false;
 | 
				
			||||||
 | 
						        bool                        RateLimited_=false;
 | 
				
			||||||
	        bool                        QueryBlockInitialized_=false;
 | 
						        bool                        QueryBlockInitialized_=false;
 | 
				
			||||||
	        Poco::Net::HTTPServerRequest    *Request= nullptr;
 | 
						        Poco::Net::HTTPServerRequest    *Request= nullptr;
 | 
				
			||||||
	        Poco::Net::HTTPServerResponse   *Response= nullptr;
 | 
						        Poco::Net::HTTPServerResponse   *Response= nullptr;
 | 
				
			||||||
	        bool                        AlwaysAuthorize_=true;
 | 
						        bool                        AlwaysAuthorize_=true;
 | 
				
			||||||
	        Poco::JSON::Parser          IncomingParser_;
 | 
						        Poco::JSON::Parser          IncomingParser_;
 | 
				
			||||||
	        RESTAPI_GenericServer       & Server_;
 | 
						        RESTAPI_GenericServer       & Server_;
 | 
				
			||||||
 | 
						        RateLimit                   MyRates_;
 | 
				
			||||||
	    };
 | 
						    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
 | 
						    class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
 | 
				
			||||||
@@ -1890,9 +2087,8 @@ namespace OpenWifi {
 | 
				
			|||||||
	    inline void initialize(Poco::Util::Application & self) override;
 | 
						    inline void initialize(Poco::Util::Application & self) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    static KafkaManager *instance() {
 | 
						    static KafkaManager *instance() {
 | 
				
			||||||
	        if(instance_== nullptr)
 | 
						        static KafkaManager instance;
 | 
				
			||||||
	            instance_ = new KafkaManager;
 | 
						        return &instance;
 | 
				
			||||||
	        return instance_;
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline int Start() override {
 | 
						    inline int Start() override {
 | 
				
			||||||
@@ -1967,7 +2163,6 @@ namespace OpenWifi {
 | 
				
			|||||||
	    // void WakeUp();
 | 
						    // void WakeUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
	    static KafkaManager 			*instance_;
 | 
					 | 
				
			||||||
	    std::mutex 						ProducerMutex_;
 | 
						    std::mutex 						ProducerMutex_;
 | 
				
			||||||
	    std::mutex						ConsumerMutex_;
 | 
						    std::mutex						ConsumerMutex_;
 | 
				
			||||||
	    bool 							KafkaEnabled_ = false;
 | 
						    bool 							KafkaEnabled_ = false;
 | 
				
			||||||
@@ -1995,7 +2190,6 @@ namespace OpenWifi {
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline KafkaManager * KafkaManager() { return KafkaManager::instance(); }
 | 
						inline KafkaManager * KafkaManager() { return KafkaManager::instance(); }
 | 
				
			||||||
	inline 	class KafkaManager *KafkaManager::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AuthClient : public SubSystemServer {
 | 
						class AuthClient : public SubSystemServer {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@@ -2005,10 +2199,8 @@ namespace OpenWifi {
 | 
				
			|||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    static AuthClient *instance() {
 | 
						    static AuthClient *instance() {
 | 
				
			||||||
	        if (instance_ == nullptr) {
 | 
						        static AuthClient instance;
 | 
				
			||||||
	            instance_ = new AuthClient;
 | 
						        return &instance;
 | 
				
			||||||
	        }
 | 
					 | 
				
			||||||
	        return instance_;
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline int Start() override {
 | 
						    inline int Start() override {
 | 
				
			||||||
@@ -2086,12 +2278,10 @@ namespace OpenWifi {
 | 
				
			|||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
	    static AuthClient 					*instance_;
 | 
					 | 
				
			||||||
	    OpenWifi::SecurityObjects::UserInfoCache 		UserCache_;
 | 
						    OpenWifi::SecurityObjects::UserInfoCache 		UserCache_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline AuthClient * AuthClient() { return AuthClient::instance(); }
 | 
						inline AuthClient * AuthClient() { return AuthClient::instance(); }
 | 
				
			||||||
	inline class AuthClient * AuthClient::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class ALBRequestHandler: public Poco::Net::HTTPRequestHandler
 | 
						class ALBRequestHandler: public Poco::Net::HTTPRequestHandler
 | 
				
			||||||
	        /// Return a HTML document with the current date and time.
 | 
						        /// Return a HTML document with the current date and time.
 | 
				
			||||||
@@ -2148,10 +2338,8 @@ namespace OpenWifi {
 | 
				
			|||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    static ALBHealthCheckServer *instance() {
 | 
						    static ALBHealthCheckServer *instance() {
 | 
				
			||||||
	        if (instance_ == nullptr) {
 | 
						        static ALBHealthCheckServer instance;
 | 
				
			||||||
	            instance_ = new ALBHealthCheckServer;
 | 
						        return &instance;
 | 
				
			||||||
	        }
 | 
					 | 
				
			||||||
	        return instance_;
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline int Start() override;
 | 
						    inline int Start() override;
 | 
				
			||||||
@@ -2162,14 +2350,12 @@ namespace OpenWifi {
 | 
				
			|||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
	    static ALBHealthCheckServer *instance_;
 | 
					 | 
				
			||||||
	    std::unique_ptr<Poco::Net::HTTPServer>   	Server_;
 | 
						    std::unique_ptr<Poco::Net::HTTPServer>   	Server_;
 | 
				
			||||||
	    std::unique_ptr<Poco::Net::ServerSocket> 	Socket_;
 | 
						    std::unique_ptr<Poco::Net::ServerSocket> 	Socket_;
 | 
				
			||||||
	    int                                     	Port_ = 0;
 | 
						    int                                     	Port_ = 0;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
 | 
						inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
 | 
				
			||||||
	inline class ALBHealthCheckServer * ALBHealthCheckServer::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
 | 
						Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
 | 
				
			||||||
                                           Poco::Logger & L, RESTAPI_GenericServer & S);
 | 
					                                           Poco::Logger & L, RESTAPI_GenericServer & S);
 | 
				
			||||||
@@ -2181,10 +2367,8 @@ namespace OpenWifi {
 | 
				
			|||||||
	class RESTAPI_server : public SubSystemServer {
 | 
						class RESTAPI_server : public SubSystemServer {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
	    static RESTAPI_server *instance() {
 | 
						    static RESTAPI_server *instance() {
 | 
				
			||||||
	        if (instance_ == nullptr) {
 | 
						        static RESTAPI_server instance;
 | 
				
			||||||
	            instance_ = new RESTAPI_server;
 | 
						        return &instance;
 | 
				
			||||||
	        }
 | 
					 | 
				
			||||||
	        return instance_;
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
	    int Start() override;
 | 
						    int Start() override;
 | 
				
			||||||
	    inline void Stop() override {
 | 
						    inline void Stop() override {
 | 
				
			||||||
@@ -2202,7 +2386,6 @@ namespace OpenWifi {
 | 
				
			|||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
	    static RESTAPI_server *instance_;
 | 
					 | 
				
			||||||
	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_;
 | 
						    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_;
 | 
				
			||||||
	    Poco::ThreadPool	    Pool_;
 | 
						    Poco::ThreadPool	    Pool_;
 | 
				
			||||||
	    RESTAPI_GenericServer   Server_;
 | 
						    RESTAPI_GenericServer   Server_;
 | 
				
			||||||
@@ -2235,9 +2418,6 @@ namespace OpenWifi {
 | 
				
			|||||||
	    RESTAPI_GenericServer   &Server_;
 | 
						    RESTAPI_GenericServer   &Server_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	inline class RESTAPI_server *RESTAPI_server::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inline int RESTAPI_server::Start() {
 | 
						inline int RESTAPI_server::Start() {
 | 
				
			||||||
	    Logger_.information("Starting.");
 | 
						    Logger_.information("Starting.");
 | 
				
			||||||
	    Server_.InitLogging();
 | 
						    Server_.InitLogging();
 | 
				
			||||||
@@ -2269,10 +2449,8 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
	    static RESTAPI_InternalServer *instance() {
 | 
						    static RESTAPI_InternalServer *instance() {
 | 
				
			||||||
	        if (instance_ == nullptr) {
 | 
						        static RESTAPI_InternalServer instance;
 | 
				
			||||||
	            instance_ = new RESTAPI_InternalServer;
 | 
						        return &instance;
 | 
				
			||||||
	        }
 | 
					 | 
				
			||||||
	        return instance_;
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    inline int Start() override;
 | 
						    inline int Start() override;
 | 
				
			||||||
@@ -2290,7 +2468,6 @@ namespace OpenWifi {
 | 
				
			|||||||
	        return RESTAPI_internal_server(Path, Bindings, Logger_, Server_);
 | 
						        return RESTAPI_internal_server(Path, Bindings, Logger_, Server_);
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
	    static RESTAPI_InternalServer *instance_;
 | 
					 | 
				
			||||||
	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_;
 | 
						    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_;
 | 
				
			||||||
	    Poco::ThreadPool	    Pool_;
 | 
						    Poco::ThreadPool	    Pool_;
 | 
				
			||||||
	    RESTAPI_GenericServer   Server_;
 | 
						    RESTAPI_GenericServer   Server_;
 | 
				
			||||||
@@ -2301,8 +2478,6 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline class RESTAPI_InternalServer* RESTAPI_InternalServer::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); };
 | 
						inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
						class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
				
			||||||
@@ -2357,6 +2532,8 @@ namespace OpenWifi {
 | 
				
			|||||||
		uint64_t 		LastUpdate=0;
 | 
							uint64_t 		LastUpdate=0;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class SubSystemServer;
 | 
						class SubSystemServer;
 | 
				
			||||||
	typedef std::map<uint64_t, MicroServiceMeta>	MicroServiceMetaMap;
 | 
						typedef std::map<uint64_t, MicroServiceMeta>	MicroServiceMetaMap;
 | 
				
			||||||
	typedef std::vector<MicroServiceMeta>			MicroServiceMetaVec;
 | 
						typedef std::vector<MicroServiceMeta>			MicroServiceMetaVec;
 | 
				
			||||||
@@ -2918,6 +3095,22 @@ namespace OpenWifi {
 | 
				
			|||||||
	    return Application::EXIT_OK;
 | 
						    return Application::EXIT_OK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AppServiceRegistry::AppServiceRegistry() {
 | 
				
			||||||
 | 
							FileName = MicroService::instance().DataDir() + "/registry.json";
 | 
				
			||||||
 | 
							Poco::File F(FileName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								if(F.exists()) {
 | 
				
			||||||
 | 
									std::ostringstream  OS;
 | 
				
			||||||
 | 
									std::ifstream       IF(FileName);
 | 
				
			||||||
 | 
									Poco::StreamCopier::copyStream(IF, OS);
 | 
				
			||||||
 | 
									Registry_ = nlohmann::json::parse(OS.str());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (...) {
 | 
				
			||||||
 | 
								Registry_ = nlohmann::json::parse("{}");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline void SubSystemServer::initialize(Poco::Util::Application &self) {
 | 
						inline void SubSystemServer::initialize(Poco::Util::Application &self) {
 | 
				
			||||||
	    Logger_.notice("Initializing...");
 | 
						    Logger_.notice("Initializing...");
 | 
				
			||||||
	    auto i = 0;
 | 
						    auto i = 0;
 | 
				
			||||||
@@ -3178,7 +3371,8 @@ namespace OpenWifi {
 | 
				
			|||||||
	                        auto InsertResult = CertNames.insert(CertFileName);
 | 
						                        auto InsertResult = CertNames.insert(CertFileName);
 | 
				
			||||||
	                        if(InsertResult.second) {
 | 
						                        if(InsertResult.second) {
 | 
				
			||||||
	                            Poco::JSON::Object  Inner;
 | 
						                            Poco::JSON::Object  Inner;
 | 
				
			||||||
	                            Inner.set("filename", CertFileName);
 | 
						                            Poco::Path  F(CertFileName);
 | 
				
			||||||
 | 
						                            Inner.set("filename", F.getFileName());
 | 
				
			||||||
	                            Poco::Crypto::X509Certificate   C(CertFileName);
 | 
						                            Poco::Crypto::X509Certificate   C(CertFileName);
 | 
				
			||||||
	                            auto ExpiresOn = C.expiresOn();
 | 
						                            auto ExpiresOn = C.expiresOn();
 | 
				
			||||||
	                            Inner.set("expiresOn",ExpiresOn.timestamp().epochTime());
 | 
						                            Inner.set("expiresOn",ExpiresOn.timestamp().epochTime());
 | 
				
			||||||
@@ -3477,7 +3671,7 @@ namespace OpenWifi {
 | 
				
			|||||||
                                               Utils::FormatIPv6(Request->clientAddress().toString()),
 | 
					                                               Utils::FormatIPv6(Request->clientAddress().toString()),
 | 
				
			||||||
                                               Request->getMethod(), Request->getURI()));
 | 
					                                               Request->getMethod(), Request->getURI()));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                UnAuthorized();
 | 
					                UnAuthorized("Invalid token", INVALID_TOKEN);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -3487,38 +3681,12 @@ namespace OpenWifi {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::Utils {
 | 
					namespace OpenWifi::Utils {
 | 
				
			||||||
        inline void SaveSystemId(uint64_t Id) {
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                std::ofstream O;
 | 
					 | 
				
			||||||
                O.open(MicroService::instance().DataDir() + "/system.id",std::ios::binary | std::ios::trunc);
 | 
					 | 
				
			||||||
                O << Id;
 | 
					 | 
				
			||||||
                O.close();
 | 
					 | 
				
			||||||
            } catch (...)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                std::cout << "Could not save system ID" << std::endl;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] inline uint64_t GetSystemId() {
 | 
						[[nodiscard]] inline uint64_t GetSystemId() {
 | 
				
			||||||
		uint64_t ID=0;
 | 
							uint64_t ID=0;
 | 
				
			||||||
 | 
							if(!AppServiceRegistry().Get("systemid",ID)) {
 | 
				
			||||||
            // if the system ID file exists, open and read it.
 | 
					 | 
				
			||||||
            Poco::File	SID( MicroService::instance().DataDir() + "/system.id");
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                if (SID.exists()) {
 | 
					 | 
				
			||||||
                    std::ifstream I;
 | 
					 | 
				
			||||||
                    I.open(SID.path());
 | 
					 | 
				
			||||||
                    I >> ID;
 | 
					 | 
				
			||||||
                    I.close();
 | 
					 | 
				
			||||||
                    if (ID == 0)
 | 
					 | 
				
			||||||
			return InitializeSystemId();
 | 
								return InitializeSystemId();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return ID;
 | 
							return ID;
 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    return InitializeSystemId();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } catch (...) {
 | 
					 | 
				
			||||||
                return InitializeSystemId();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,13 +47,18 @@ namespace OpenWifi::RESTAPI::Errors {
 | 
				
			|||||||
    static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
 | 
					    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 InvalidUserRole{"Invalid userRole."};
 | 
				
			||||||
    static const std::string InvalidEmailAddress{"Invalid email address."};
 | 
					    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 PasswordRejected{"Password was rejected. This maybe an old password."};
 | 
				
			||||||
    static const std::string InvalidIPRanges{"Invalid IP range specifications."};
 | 
					    static const std::string InvalidIPRanges{"Invalid IP range specifications."};
 | 
				
			||||||
    static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
 | 
					    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 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 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."};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //OWPROV_RESTAPI_ERRORS_H
 | 
					#endif //OWPROV_RESTAPI_ERRORS_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,8 +103,6 @@ namespace OpenWifi {
 | 
				
			|||||||
        DBType                                              dbType_ = sqlite;
 | 
					        DBType                                              dbType_ = sqlite;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//    inline StorageClass * Storage() { return StorageClass::instance(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef	SMALL_BUILD
 | 
					#ifdef	SMALL_BUILD
 | 
				
			||||||
    int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
 | 
					    int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
 | 
				
			||||||
    int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
 | 
					    int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										186
									
								
								src/storage/storage_actionLinks.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								src/storage/storage_actionLinks.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2021-11-08.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "storage_actionLinks.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Convert(const ActionLinkRecord &T, SecurityObjects::ActionLink &U) {
 | 
				
			||||||
 | 
					        U.id = T.get<0>();
 | 
				
			||||||
 | 
					        U.action = T.get<1>();
 | 
				
			||||||
 | 
					        U.userId = T.get<2>();
 | 
				
			||||||
 | 
					        U.actionTemplate = T.get<3>();
 | 
				
			||||||
 | 
					        U.variables = RESTAPI_utils::to_stringpair_array(T.get<4>());
 | 
				
			||||||
 | 
					        U.locale = T.get<5>();
 | 
				
			||||||
 | 
					        U.message = T.get<6>();
 | 
				
			||||||
 | 
					        U.sent = T.get<7>();
 | 
				
			||||||
 | 
					        U.created = T.get<8>();
 | 
				
			||||||
 | 
					        U.expires = T.get<9>();
 | 
				
			||||||
 | 
					        U.completed = T.get<10>();
 | 
				
			||||||
 | 
					        U.canceled = T.get<11>();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Convert(const SecurityObjects::ActionLink &U, ActionLinkRecord &T) {
 | 
				
			||||||
 | 
					        T.set<0>(U.id);
 | 
				
			||||||
 | 
					        T.set<1>(U.action);
 | 
				
			||||||
 | 
					        T.set<2>(U.userId);
 | 
				
			||||||
 | 
					        T.set<3>(U.actionTemplate);
 | 
				
			||||||
 | 
					        T.set<4>(RESTAPI_utils::to_string(U.variables));
 | 
				
			||||||
 | 
					        T.set<5>(U.locale);
 | 
				
			||||||
 | 
					        T.set<6>(U.message);
 | 
				
			||||||
 | 
					        T.set<7>(U.sent);
 | 
				
			||||||
 | 
					        T.set<8>(U.created);
 | 
				
			||||||
 | 
					        T.set<9>(U.expires);
 | 
				
			||||||
 | 
					        T.set<10>(U.completed);
 | 
				
			||||||
 | 
					        T.set<11>(U.canceled);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::CreateAction( SecurityObjects::ActionLink & A) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Insert(Sess);
 | 
				
			||||||
 | 
					            std::string St2{
 | 
				
			||||||
 | 
					                "INSERT INTO ActionLinks (" + AllActionLinksFieldsForSelect + ") VALUES(" + AllActionLinksValuesForSelect + ")"};
 | 
				
			||||||
 | 
					            ActionLinkRecord AR;
 | 
				
			||||||
 | 
					            Convert(A, AR);
 | 
				
			||||||
 | 
					            Insert << ConvertParams(St2),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(AR);
 | 
				
			||||||
 | 
					            Insert.execute();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Select(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ActionLinkRecordList ARL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string S{
 | 
				
			||||||
 | 
					                "SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where sent=0 and canceled=0 and completed=0"};
 | 
				
			||||||
 | 
					            Select << ConvertParams(S),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::into(ARL);
 | 
				
			||||||
 | 
					            Select.execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for(const auto &i:ARL) {
 | 
				
			||||||
 | 
					                SecurityObjects::ActionLink L;
 | 
				
			||||||
 | 
					                Convert(i,L);
 | 
				
			||||||
 | 
					                Links.emplace_back(L);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Select(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ActionLinkRecord AR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string St2{
 | 
				
			||||||
 | 
					                "SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where id=?"};
 | 
				
			||||||
 | 
					            Select << ConvertParams(St2),
 | 
				
			||||||
 | 
					            Poco::Data::Keywords::into(AR),
 | 
				
			||||||
 | 
					            Poco::Data::Keywords::use(ActionId);
 | 
				
			||||||
 | 
					            Select.execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(Select.rowsExtracted()==1) {
 | 
				
			||||||
 | 
					                Convert(AR, A);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::SentAction(std::string &ActionId) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Update(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint64_t Sent = std::time(nullptr);
 | 
				
			||||||
 | 
					            std::string St{"UPDATE ActionLinks set Sent=? where id=?"};
 | 
				
			||||||
 | 
					            Update << ConvertParams(St),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(Sent),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(ActionId);
 | 
				
			||||||
 | 
					            Update.execute();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::DeleteAction(std::string &ActionId) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Delete(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint64_t Sent = std::time(nullptr);
 | 
				
			||||||
 | 
					            std::string St{"DELETE FROM ActionLinks where id=?"};
 | 
				
			||||||
 | 
					            Delete << ConvertParams(St),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(ActionId);
 | 
				
			||||||
 | 
					            Delete.execute();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::CompleteAction(std::string &ActionId) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Update(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint64_t completed = std::time(nullptr);
 | 
				
			||||||
 | 
					            std::string St{"UPDATE ActionLinks set completed=? where id=?"};
 | 
				
			||||||
 | 
					            Update << ConvertParams(St),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(completed),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(ActionId);
 | 
				
			||||||
 | 
					            Update.execute();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::CancelAction(std::string &ActionId) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					            Poco::Data::Statement Update(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint64_t canceled = std::time(nullptr);
 | 
				
			||||||
 | 
					            std::string St{"UPDATE ActionLinks set canceled=? where id=?"};
 | 
				
			||||||
 | 
					            Update << ConvertParams(St),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(canceled),
 | 
				
			||||||
 | 
					                Poco::Data::Keywords::use(ActionId);
 | 
				
			||||||
 | 
					            Update.execute();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										79
									
								
								src/storage/storage_actionLinks.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/storage/storage_actionLinks.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2021-11-08.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef OWSEC_STORAGE_ACTIONLINKS_H
 | 
				
			||||||
 | 
					#define OWSEC_STORAGE_ACTIONLINKS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include "Poco/Tuple.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					    static const std::string AllActionLinksFieldsForCreation{
 | 
				
			||||||
 | 
					        "Id             varchar(36),"
 | 
				
			||||||
 | 
					        "Action         bigint,"
 | 
				
			||||||
 | 
					        "UserId         text,"
 | 
				
			||||||
 | 
					        "template       text,"
 | 
				
			||||||
 | 
					        "variables      text,"
 | 
				
			||||||
 | 
					        "locale         varchar,"
 | 
				
			||||||
 | 
					        "message        text,"
 | 
				
			||||||
 | 
					        "sent           bigint,"
 | 
				
			||||||
 | 
					        "created        bigint,"
 | 
				
			||||||
 | 
					        "expires        bigint,"
 | 
				
			||||||
 | 
					        "completed      bigint,"
 | 
				
			||||||
 | 
					        "canceled       bigint"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllActionLinksFieldsForSelect {
 | 
				
			||||||
 | 
					        "Id, "
 | 
				
			||||||
 | 
					        "Action,"
 | 
				
			||||||
 | 
					        "UserId,"
 | 
				
			||||||
 | 
					        "template,"
 | 
				
			||||||
 | 
					        "variables,"
 | 
				
			||||||
 | 
					        "locale,"
 | 
				
			||||||
 | 
					        "message,"
 | 
				
			||||||
 | 
					        "sent,"
 | 
				
			||||||
 | 
					        "created,"
 | 
				
			||||||
 | 
					        "expires,"
 | 
				
			||||||
 | 
					        "completed,"
 | 
				
			||||||
 | 
					        "canceled"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllActionLinksValuesForSelect{ "?,?,?,?,?,?,?,?,?,?,?,?" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllActionLinksFieldsForUpdate {
 | 
				
			||||||
 | 
					        "Id=?, "
 | 
				
			||||||
 | 
					        "Action=?,"
 | 
				
			||||||
 | 
					        "UserId=?,"
 | 
				
			||||||
 | 
					        "template=?,"
 | 
				
			||||||
 | 
					        "variables=?,"
 | 
				
			||||||
 | 
					        "locale=?,"
 | 
				
			||||||
 | 
					        "message=?,"
 | 
				
			||||||
 | 
					        "sent=?,"
 | 
				
			||||||
 | 
					        "created=?,"
 | 
				
			||||||
 | 
					        "expires=?,"
 | 
				
			||||||
 | 
					        "completed=?,"
 | 
				
			||||||
 | 
					        "canceled=?"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef Poco::Tuple <
 | 
				
			||||||
 | 
					                std::string,    // id
 | 
				
			||||||
 | 
					                uint64_t,       // action
 | 
				
			||||||
 | 
					                std::string,    // userId
 | 
				
			||||||
 | 
					                std::string,    // actionTemplate
 | 
				
			||||||
 | 
					                std::string,    // variables
 | 
				
			||||||
 | 
					                std::string,    // locale
 | 
				
			||||||
 | 
					                std::string,    // message
 | 
				
			||||||
 | 
					                uint64_t,       // sent
 | 
				
			||||||
 | 
					                uint64_t,       // created
 | 
				
			||||||
 | 
					                uint64_t,       // expires
 | 
				
			||||||
 | 
					                uint64_t,       // completed
 | 
				
			||||||
 | 
					                uint64_t        // canceled
 | 
				
			||||||
 | 
					            > ActionLinkRecord;
 | 
				
			||||||
 | 
					    typedef std::vector <ActionLinkRecord> ActionLinkRecordList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //OWSEC_STORAGE_ACTIONLINKS_H
 | 
				
			||||||
@@ -35,8 +35,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            uint64_t Now = std::time(nullptr);
 | 
					            uint64_t Now = std::time(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string St2{
 | 
					            std::string St2{"INSERT INTO Avatars (" + AllAvatarFieldsForSelect + ") VALUES( " + AllAvatarValuesForSelect + " )"};
 | 
				
			||||||
                    "INSERT INTO Avatars (Id,Type,Created,Name,Avatar) VALUES(?,?,?,?,?)"};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Insert << ConvertParams(St2),
 | 
					            Insert << ConvertParams(St2),
 | 
				
			||||||
                    Poco::Data::Keywords::use(Id),
 | 
					                    Poco::Data::Keywords::use(Id),
 | 
				
			||||||
@@ -58,13 +57,19 @@ namespace OpenWifi {
 | 
				
			|||||||
            Poco::Data::Session Sess = Pool_->get();
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
            Poco::Data::Statement Select(Sess);
 | 
					            Poco::Data::Statement Select(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string St2{"SELECT Avatar, Type, Name FROM Avatars WHERE Id=?"};
 | 
					            std::string St2{"SELECT " + AllAvatarFieldsForSelect + " FROM Avatars WHERE Id=?"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Poco::Data::Statement Select2(Sess);
 | 
					            Poco::Data::Statement Select2(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string TId;
 | 
				
			||||||
 | 
					            uint64_t    Created;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Select2 << ConvertParams(St2),
 | 
					            Select2 << ConvertParams(St2),
 | 
				
			||||||
                    Poco::Data::Keywords::into(L),
 | 
					                    Poco::Data::Keywords::into(TId),
 | 
				
			||||||
                    Poco::Data::Keywords::into(Type),
 | 
					                    Poco::Data::Keywords::into(Type),
 | 
				
			||||||
 | 
					                    Poco::Data::Keywords::into(Created),
 | 
				
			||||||
                    Poco::Data::Keywords::into(Name),
 | 
					                    Poco::Data::Keywords::into(Name),
 | 
				
			||||||
 | 
					                    Poco::Data::Keywords::into(L),
 | 
				
			||||||
                    Poco::Data::Keywords::use(Id);
 | 
					                    Poco::Data::Keywords::use(Id);
 | 
				
			||||||
            Select2.execute();
 | 
					            Select2.execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,33 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllAvatarFieldsForCreation_sqlite{
 | 
				
			||||||
 | 
					        "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
				
			||||||
 | 
					        "Type			VARCHAR, "
 | 
				
			||||||
 | 
					        "Created 		BIGINT, "
 | 
				
			||||||
 | 
					        "Name           VARCHAR, "
 | 
				
			||||||
 | 
					        "Avatar     	BLOB"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllAvatarFieldsForCreation_mysql{
 | 
				
			||||||
 | 
					        "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
				
			||||||
 | 
					        "Type			VARCHAR, "
 | 
				
			||||||
 | 
					        "Created 		BIGINT, "
 | 
				
			||||||
 | 
					        "Name           VARCHAR, "
 | 
				
			||||||
 | 
					        "Avatar     	LONGBLOB"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllAvatarFieldsForCreation_pgsql{
 | 
				
			||||||
 | 
					        "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
				
			||||||
 | 
					        "Type			VARCHAR, "
 | 
				
			||||||
 | 
					        "Created 		BIGINT, "
 | 
				
			||||||
 | 
					        "Name           VARCHAR, "
 | 
				
			||||||
 | 
					        "Avatar     	BYTEA"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const std::string AllAvatarFieldsForSelect{ " Id,Type,Created,Name,Avatar " };
 | 
				
			||||||
 | 
					    static const std::string AllAvatarValuesForSelect{ "?,?,?,?,?" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "storage_users.h"
 | 
					#include "storage_users.h"
 | 
				
			||||||
#include "storage_avatar.h"
 | 
					#include "storage_avatar.h"
 | 
				
			||||||
 | 
					#include "storage_actionLinks.h"
 | 
				
			||||||
 | 
					#include "storage_tokens.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,6 +14,7 @@ namespace OpenWifi {
 | 
				
			|||||||
        Create_UserTable();
 | 
					        Create_UserTable();
 | 
				
			||||||
        Create_AvatarTable();
 | 
					        Create_AvatarTable();
 | 
				
			||||||
        Create_TokensTable();
 | 
					        Create_TokensTable();
 | 
				
			||||||
 | 
					        Create_ActionLinkTable();
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,83 +43,51 @@ namespace OpenWifi {
 | 
				
			|||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int Storage::Create_ActionLinkTable() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Sess << "CREATE TABLE IF NOT EXISTS ActionLinks ( "
 | 
				
			||||||
 | 
					                    + AllActionLinksFieldsForCreation + " ) ",
 | 
				
			||||||
 | 
					            Poco::Data::Keywords::now;
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        } catch(const Poco::Exception &E) {
 | 
				
			||||||
 | 
					            Logger_.log(E);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int Storage::Create_AvatarTable() {
 | 
					    int Storage::Create_AvatarTable() {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                Poco::Data::Session Sess = Pool_->get();
 | 
					                Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if(dbType_==sqlite) {
 | 
					                if(dbType_==sqlite) {
 | 
				
			||||||
                    Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
 | 
					                    Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_sqlite +
 | 
				
			||||||
                            "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
					 | 
				
			||||||
                            "Type			VARCHAR, "
 | 
					 | 
				
			||||||
                            "Created 		BIGINT, "
 | 
					 | 
				
			||||||
                            "Name           VARCHAR, "
 | 
					 | 
				
			||||||
                            "Avatar     	BLOB"
 | 
					 | 
				
			||||||
                            ") ", Poco::Data::Keywords::now;
 | 
					                            ") ", Poco::Data::Keywords::now;
 | 
				
			||||||
                } else if(dbType_==mysql) {
 | 
					                } else if(dbType_==mysql) {
 | 
				
			||||||
                    Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
 | 
					                    Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_mysql +
 | 
				
			||||||
                            "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
					 | 
				
			||||||
                            "Type			VARCHAR, "
 | 
					 | 
				
			||||||
                            "Created 		BIGINT, "
 | 
					 | 
				
			||||||
                            "Name           VARCHAR, "
 | 
					 | 
				
			||||||
                            "Avatar     	LONGBLOB"
 | 
					 | 
				
			||||||
                            ") ", Poco::Data::Keywords::now;
 | 
					                            ") ", Poco::Data::Keywords::now;
 | 
				
			||||||
                } else if(dbType_==pgsql) {
 | 
					                } else if(dbType_==pgsql) {
 | 
				
			||||||
                    Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
 | 
					                    Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_pgsql +
 | 
				
			||||||
                            "Id			    VARCHAR(36) PRIMARY KEY, "
 | 
					 | 
				
			||||||
                            "Type			VARCHAR, "
 | 
					 | 
				
			||||||
                            "Created 		BIGINT, "
 | 
					 | 
				
			||||||
                            "Name           VARCHAR, "
 | 
					 | 
				
			||||||
                            "Avatar     	BYTEA"
 | 
					 | 
				
			||||||
                            ") ", Poco::Data::Keywords::now;
 | 
					                            ") ", Poco::Data::Keywords::now;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
            } catch(const Poco::Exception &E) {
 | 
					            } catch(const Poco::Exception &E) {
 | 
				
			||||||
                Logger_.log(E);
 | 
					                Logger_.log(E);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return 0;
 | 
					            return 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int Storage::Create_TokensTable() {
 | 
					        int Storage::Create_TokensTable() {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            Poco::Data::Session Sess = Pool_->get();
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
            if(dbType_==sqlite) {
 | 
					                Sess << "CREATE TABLE IF NOT EXISTS Tokens (" +
 | 
				
			||||||
                Sess << "CREATE TABLE IF NOT EXISTS Tokens ("
 | 
					                            AllTokensFieldsForCreation +
 | 
				
			||||||
                        "Token			    TEXT PRIMARY KEY, "
 | 
					 | 
				
			||||||
                        "RefreshToken       TEXT, "
 | 
					 | 
				
			||||||
                        "TokenType          TEXT, "
 | 
					 | 
				
			||||||
                        "UserName           TEXT, "
 | 
					 | 
				
			||||||
                        "Created 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "Expires 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "IdleTimeOut        BIGINT, "
 | 
					 | 
				
			||||||
                        "RevocationDate 	BIGINT "
 | 
					 | 
				
			||||||
                        ") ", Poco::Data::Keywords::now;
 | 
					                        ") ", Poco::Data::Keywords::now;
 | 
				
			||||||
            } else if(dbType_==mysql) {
 | 
					 | 
				
			||||||
                Sess << "CREATE TABLE IF NOT EXISTS Tokens ("
 | 
					 | 
				
			||||||
                        "Token			    TEXT PRIMARY KEY, "
 | 
					 | 
				
			||||||
                        "RefreshToken       TEXT, "
 | 
					 | 
				
			||||||
                        "TokenType          TEXT, "
 | 
					 | 
				
			||||||
                        "UserName           TEXT, "
 | 
					 | 
				
			||||||
                        "Created 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "Expires 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "IdleTimeOut        BIGINT, "
 | 
					 | 
				
			||||||
                        "RevocationDate 	BIGINT "
 | 
					 | 
				
			||||||
                        ") ", Poco::Data::Keywords::now;
 | 
					 | 
				
			||||||
            } else if(dbType_==pgsql) {
 | 
					 | 
				
			||||||
                Sess << "CREATE TABLE IF NOT EXISTS Tokens ("
 | 
					 | 
				
			||||||
                        "Token			    TEXT PRIMARY KEY, "
 | 
					 | 
				
			||||||
                        "RefreshToken       TEXT, "
 | 
					 | 
				
			||||||
                        "TokenType          TEXT, "
 | 
					 | 
				
			||||||
                        "UserName           TEXT, "
 | 
					 | 
				
			||||||
                        "Created 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "Expires 		    BIGINT, "
 | 
					 | 
				
			||||||
                        "IdleTimeOut        BIGINT, "
 | 
					 | 
				
			||||||
                        "RevocationDate 	BIGINT "
 | 
					 | 
				
			||||||
                        ") ", Poco::Data::Keywords::now;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        } catch(const Poco::Exception &E) {
 | 
					        } catch(const Poco::Exception &E) {
 | 
				
			||||||
            Logger_.log(E);
 | 
					            Logger_.log(E);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return 0;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "../StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "storage/storage_tokens.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,7 +23,7 @@ namespace OpenWifi {
 | 
				
			|||||||
            uint64_t Z = 0;
 | 
					            uint64_t Z = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string St2{
 | 
					            std::string St2{
 | 
				
			||||||
                "INSERT INTO Tokens (Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate) VALUES(?,?,?,?,?,?,?,?)"};
 | 
					                "INSERT INTO Tokens (" + AllTokensFieldsForSelect + ") VALUES(" + AllTokensValuesForSelect + ")"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Insert << ConvertParams(St2),
 | 
					            Insert << ConvertParams(St2),
 | 
				
			||||||
                Poco::Data::Keywords::use(Token),
 | 
					                Poco::Data::Keywords::use(Token),
 | 
				
			||||||
@@ -49,7 +50,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            uint32_t RevocationDate = 0 ;
 | 
					            uint32_t RevocationDate = 0 ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string St2{"SELECT Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate From Tokens WHERE Token=?"};
 | 
					            std::string St2{"SELECT " + AllTokensValuesForSelect + " From Tokens WHERE Token=?"};
 | 
				
			||||||
            Select << ConvertParams(St2),
 | 
					            Select << ConvertParams(St2),
 | 
				
			||||||
                Poco::Data::Keywords::into(UInfo.webtoken.access_token_),
 | 
					                Poco::Data::Keywords::into(UInfo.webtoken.access_token_),
 | 
				
			||||||
                Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_),
 | 
					                Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										30
									
								
								src/storage/storage_tokens.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/storage/storage_tokens.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2021-11-08.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef OWSEC_STORAGE_TOKENS_H
 | 
				
			||||||
 | 
					#define OWSEC_STORAGE_TOKENS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include "Poco/Tuple.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static std::string AllTokensFieldsForCreation{                        "Token			    TEXT PRIMARY KEY, "
 | 
				
			||||||
 | 
					                                                                          "RefreshToken       TEXT, "
 | 
				
			||||||
 | 
					                                                                          "TokenType          TEXT, "
 | 
				
			||||||
 | 
					                                                                          "UserName           TEXT, "
 | 
				
			||||||
 | 
					                                                                          "Created 		    BIGINT, "
 | 
				
			||||||
 | 
					                                                                          "Expires 		    BIGINT, "
 | 
				
			||||||
 | 
					                                                                          "IdleTimeOut        BIGINT, "
 | 
				
			||||||
 | 
					                                                                          "RevocationDate 	BIGINT "
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    static std::string AllTokensFieldsForSelect {"Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate"};
 | 
				
			||||||
 | 
					    static std::string AllTokensValuesForSelect{"?,?,?,?,?,?,?,?"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //OWSEC_STORAGE_TOKENS_H
 | 
				
			||||||
@@ -80,7 +80,35 @@ namespace OpenWifi {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser) {
 | 
					    std::string DefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //  if we do not find a default user, then we need to create one based on the
 | 
				
			||||||
 | 
					    //  property file. We must set its flag to "must change password", this user has root privilege.
 | 
				
			||||||
 | 
					    //  if the "DEFAULT-USER-UUID", we keep the UUID of that user. We want to hide the UUID of the default root user
 | 
				
			||||||
 | 
					    bool Storage::InitializeDefaultUser() {
 | 
				
			||||||
 | 
					        SecurityObjects::UserInfo   U;
 | 
				
			||||||
 | 
					        bool DefaultUserCreated = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated);
 | 
				
			||||||
 | 
					        if(!GetUserById(DefaultUseridStockUUID,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 = DefaultUseridStockUUID;
 | 
				
			||||||
 | 
					            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;
 | 
				
			||||||
 | 
					            CreateUser("SYSTEM",U, true);
 | 
				
			||||||
 | 
					            AppServiceRegistry().Set("defaultusercreated",true);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready ) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            Poco::Data::Session Sess = Pool_->get();
 | 
					            Poco::Data::Session Sess = Pool_->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,20 +131,24 @@ namespace OpenWifi {
 | 
				
			|||||||
            if(!Records.empty())
 | 
					            if(!Records.empty())
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!PasswordHashedAlready) {
 | 
				
			||||||
                NewUser.Id = MicroService::instance().CreateUUID();
 | 
					                NewUser.Id = MicroService::instance().CreateUUID();
 | 
				
			||||||
                NewUser.creationDate = std::time(nullptr);
 | 
					                NewUser.creationDate = std::time(nullptr);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  if there is a password, we assume that we do not want email verification,
 | 
					            //  if there is a password, we assume that we do not want email verification,
 | 
				
			||||||
            //  if there is no password, we will do email verification
 | 
					            //  if there is no password, we will do email verification
 | 
				
			||||||
            if(NewUser.currentPassword.empty()) {
 | 
					            if(NewUser.currentPassword.empty()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                NewUser.currentPassword = AuthService()->ComputePasswordHash(NewUser.email,NewUser.currentPassword);
 | 
					                if(!PasswordHashedAlready) {
 | 
				
			||||||
 | 
					                    NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword);
 | 
				
			||||||
                    NewUser.lastPasswords.clear();
 | 
					                    NewUser.lastPasswords.clear();
 | 
				
			||||||
                    NewUser.lastPasswords.push_back(NewUser.currentPassword);
 | 
					                    NewUser.lastPasswords.push_back(NewUser.currentPassword);
 | 
				
			||||||
                    NewUser.lastPasswordChange = std::time(nullptr);
 | 
					                    NewUser.lastPasswordChange = std::time(nullptr);
 | 
				
			||||||
                    NewUser.validated = true;
 | 
					                    NewUser.validated = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto Notes = RESTAPI_utils::to_string(NewUser.notes);
 | 
					            auto Notes = RESTAPI_utils::to_string(NewUser.notes);
 | 
				
			||||||
            auto UserType = SecurityObjects::UserTypeToString(NewUser.userRole);
 | 
					            auto UserType = SecurityObjects::UserTypeToString(NewUser.userRole);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,20 +105,6 @@ namespace OpenWifi {
 | 
				
			|||||||
            "oauthType=?, "
 | 
					            "oauthType=?, "
 | 
				
			||||||
            "oauthUserInfo=? "};
 | 
					            "oauthUserInfo=? "};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const std::string AllActionLinksFieldsForCreation{
 | 
					 | 
				
			||||||
            "Id          varchar(36),"
 | 
					 | 
				
			||||||
            "Action         varchar,"
 | 
					 | 
				
			||||||
            "UserId         varchar,"
 | 
					 | 
				
			||||||
            "template       varchar,"
 | 
					 | 
				
			||||||
            "locale         varchar,"
 | 
					 | 
				
			||||||
            "message        text,"
 | 
					 | 
				
			||||||
            "sent           bigint,"
 | 
					 | 
				
			||||||
            "created        bigint,"
 | 
					 | 
				
			||||||
            "expires        bigint,"
 | 
					 | 
				
			||||||
            "completed      bigint,"
 | 
					 | 
				
			||||||
            "canceled       bigint"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    typedef Poco::Tuple <
 | 
					    typedef Poco::Tuple <
 | 
				
			||||||
        std::string,    // Id = 0;
 | 
					        std::string,    // Id = 0;
 | 
				
			||||||
        std::string,    // name;
 | 
					        std::string,    // name;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,8 +58,8 @@ testlogin() {
 | 
				
			|||||||
    curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
 | 
					    curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
 | 
				
			||||||
        -H "Content-Type: application/json" \
 | 
					        -H "Content-Type: application/json" \
 | 
				
			||||||
        -d "$payload" > ${result_file}
 | 
					        -d "$payload" > ${result_file}
 | 
				
			||||||
    userMustChangePassword=$(cat ${result_file} | jq -r '.userMustChangePassword')
 | 
					    userMustChangePassword=$(cat ${result_file} | jq -r '.ErrorCode')
 | 
				
			||||||
    if [[ ${userMustChangePassword} == "true" ]]
 | 
					    if [[ ${userMustChangePassword} == "1" ]]
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
        echo "User must change password to login..."
 | 
					        echo "User must change password to login..."
 | 
				
			||||||
        if [[ "$3" == "" ]]
 | 
					        if [[ "$3" == "" ]]
 | 
				
			||||||
@@ -78,7 +78,10 @@ testlogin() {
 | 
				
			|||||||
        curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
 | 
					        curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
 | 
				
			||||||
                -H "Content-Type: application/json" \
 | 
					                -H "Content-Type: application/json" \
 | 
				
			||||||
                -d "$payload" > ${result_file}
 | 
					                -d "$payload" > ${result_file}
 | 
				
			||||||
        jq < ${result_file}
 | 
					        token=$(cat ${result_file} | jq -r '.access_token')
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        payload="{ \"userId\" : \"$1\" , \"password\" : \"$2\" }"
 | 
				
			||||||
 | 
					        token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${OWSEC}/api/v1/oauth2" | jq -r '.access_token')
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    jq < ${result_file}
 | 
					    jq < ${result_file}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -372,6 +375,7 @@ case "$1" in
 | 
				
			|||||||
    "getsubsystemnames") login; getsubsystemnames; logout ;;
 | 
					    "getsubsystemnames") login; getsubsystemnames; logout ;;
 | 
				
			||||||
    "reloadsubsystem") login; reloadsubsystem "$2"; logout ;;
 | 
					    "reloadsubsystem") login; reloadsubsystem "$2"; logout ;;
 | 
				
			||||||
    "systeminfo") login; systeminfo ; logout;;
 | 
					    "systeminfo") login; systeminfo ; logout;;
 | 
				
			||||||
 | 
					    "testburst") login; login; login; login; login; login; login; login; login; login; login; login; login; login; login; login;;
 | 
				
			||||||
    "help") login; help  ; logout ;;
 | 
					    "help") login; help  ; logout ;;
 | 
				
			||||||
    *) help ;;
 | 
					    *) help ;;
 | 
				
			||||||
esac
 | 
					esac
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,38 @@
 | 
				
			|||||||
            opacity: 0.8;
 | 
					            opacity: 0.8;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .imgcontainer {
 | 
					        .img-container {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            margin-top: 5%;
 | 
				
			||||||
            text-align: center;
 | 
					            text-align: center;
 | 
				
			||||||
            margin: 24px 0 12px 0;
 | 
					            display: block;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-card {
 | 
				
			||||||
 | 
					            padding: 30px;
 | 
				
			||||||
 | 
					            box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            width: 50%;
 | 
				
			||||||
 | 
					            border: 1em;
 | 
				
			||||||
 | 
					            background-color: white;
 | 
				
			||||||
 | 
					            width: 40%;
 | 
				
			||||||
 | 
					            height: auto;
 | 
				
			||||||
 | 
					            margin-left: auto;
 | 
				
			||||||
 | 
					            margin-right: auto;
 | 
				
			||||||
 | 
					            margin-bottom: auto;
 | 
				
			||||||
 | 
					            margin-top: 50px;
 | 
				
			||||||
 | 
					            position: relative;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        .info-list {
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-title {
 | 
				
			||||||
 | 
					            padding-bottom: 20px;
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        img.avatar {
 | 
					        img.avatar {
 | 
				
			||||||
@@ -48,6 +77,10 @@
 | 
				
			|||||||
            padding-top: 16px;
 | 
					            padding-top: 16px;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body {
 | 
				
			||||||
 | 
					            background-color: #ebedef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Change styles for span and cancel button on extra small screens */
 | 
					        /* Change styles for span and cancel button on extra small screens */
 | 
				
			||||||
        @media screen and (max-width: 300px) {
 | 
					        @media screen and (max-width: 300px) {
 | 
				
			||||||
            span.password1 {
 | 
					            span.password1 {
 | 
				
			||||||
@@ -62,13 +95,13 @@
 | 
				
			|||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="imgcontainer">
 | 
					<div class="img-container">
 | 
				
			||||||
    <img src="open-wifi.svg" alt="OpenWifi">
 | 
					    <img src="/wwwassets/the_logo.png" alt="OpenWifi">
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div>
 | 
					<div class="info-card">
 | 
				
			||||||
    <p>Site access rules:</p>
 | 
					    <h2 class="info-title">Site Access rules</h2>
 | 
				
			||||||
    <ul>
 | 
					    <ul class="info-list">
 | 
				
			||||||
        <li>Must be a TIP Member.</li>
 | 
					        <li>Must be a TIP Member.</li>
 | 
				
			||||||
    </ul>
 | 
					    </ul>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,8 +30,10 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .imgcontainer {
 | 
					        .imgcontainer {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            margin-top: 5%;
 | 
				
			||||||
            text-align: center;
 | 
					            text-align: center;
 | 
				
			||||||
            margin: 24px 0 12px 0;
 | 
					            display: block;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        img.avatar {
 | 
					        img.avatar {
 | 
				
			||||||
@@ -43,6 +45,37 @@
 | 
				
			|||||||
            padding: 16px;
 | 
					            padding: 16px;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-card {
 | 
				
			||||||
 | 
					            padding: 30px;
 | 
				
			||||||
 | 
					            box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            width: 50%;
 | 
				
			||||||
 | 
					            border: 1em;
 | 
				
			||||||
 | 
					            background-color: white;
 | 
				
			||||||
 | 
					            width: 40%;
 | 
				
			||||||
 | 
					            height: auto;
 | 
				
			||||||
 | 
					            margin-left: auto;
 | 
				
			||||||
 | 
					            margin-right: auto;
 | 
				
			||||||
 | 
					            margin-bottom: auto;
 | 
				
			||||||
 | 
					            margin-top: 50px;
 | 
				
			||||||
 | 
					            position: relative;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-list {
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-title {
 | 
				
			||||||
 | 
					            padding-bottom: 20px;
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        .body {
 | 
				
			||||||
 | 
					            background-color: #ebedef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        span.password1 {
 | 
					        span.password1 {
 | 
				
			||||||
            float: right;
 | 
					            float: right;
 | 
				
			||||||
            padding-top: 16px;
 | 
					            padding-top: 16px;
 | 
				
			||||||
@@ -60,16 +93,17 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body class="body">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="imgcontainer">
 | 
					<div class="imgcontainer">
 | 
				
			||||||
    <img src="open-wifi.svg" alt="OpenWifi">
 | 
					    <img src="/wwwassets/the_logo.png" alt="OpenWifi">
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div>
 | 
					
 | 
				
			||||||
    <p>Password rules:</p>
 | 
					<div class="info-card">
 | 
				
			||||||
    <ul>
 | 
					    <h2 class="info-title">Password rules</h2>
 | 
				
			||||||
        <li>Must be at least 8 characters long.</li>
 | 
					    <ul class="info-list">
 | 
				
			||||||
 | 
					        <li>Must be at least 8 characters long</li>
 | 
				
			||||||
        <li>Must contain 1 uppercase letter</li>
 | 
					        <li>Must contain 1 uppercase letter</li>
 | 
				
			||||||
        <li>Must contain 1 lowercase letter</li>
 | 
					        <li>Must contain 1 lowercase letter</li>
 | 
				
			||||||
        <li>Must contain 1 digit</li>
 | 
					        <li>Must contain 1 digit</li>
 | 
				
			||||||
@@ -78,5 +112,6 @@
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
@@ -3,8 +3,15 @@
 | 
				
			|||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
    <style>
 | 
					    <style>
 | 
				
			||||||
        body {font-family: Arial, Helvetica, sans-serif;}
 | 
					        body {
 | 
				
			||||||
        form {border: 3px solid #f1f1f1;}
 | 
					            font-family: Arial, 
 | 
				
			||||||
 | 
					            Helvetica, sans-serif;
 | 
				
			||||||
 | 
					            background-color: #ebedef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .body {
 | 
				
			||||||
 | 
					            background-color: #ebedef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        input[type=text], input[type=password] {
 | 
					        input[type=text], input[type=password] {
 | 
				
			||||||
            width: 90%;
 | 
					            width: 90%;
 | 
				
			||||||
@@ -31,15 +38,10 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .imgcontainer {
 | 
					        .imgcontainer {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            margin-top: 5%;
 | 
				
			||||||
            text-align: center;
 | 
					            text-align: center;
 | 
				
			||||||
            margin: 5px 0 5px 0;
 | 
					            display: block;
 | 
				
			||||||
            grid-column-start: 2;
 | 
					 | 
				
			||||||
            grid-column-end: 2;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .passwordlabel {
 | 
					 | 
				
			||||||
            grid-column-start: 2;
 | 
					 | 
				
			||||||
            grid-column-end: 2;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        img.avatar {
 | 
					        img.avatar {
 | 
				
			||||||
@@ -50,16 +52,22 @@
 | 
				
			|||||||
        .grid-container  {
 | 
					        .grid-container  {
 | 
				
			||||||
            display: grid;
 | 
					            display: grid;
 | 
				
			||||||
            grid-template-columns: 15% 70% 15%;
 | 
					            grid-template-columns: 15% 70% 15%;
 | 
				
			||||||
            background-color: #f3db21;
 | 
					 | 
				
			||||||
            grid-column-gap: 5px;
 | 
					            grid-column-gap: 5px;
 | 
				
			||||||
            padding: 10px;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .grid-container > div {
 | 
					 | 
				
			||||||
            background-color: rgba(255, 255, 255, 0.8);
 | 
					            background-color: rgba(255, 255, 255, 0.8);
 | 
				
			||||||
            text-align: center;
 | 
					            text-align: center;
 | 
				
			||||||
            padding: 20px 0;
 | 
					            padding: 30px;
 | 
				
			||||||
            font-size: 30px;
 | 
					            box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            width: 50%;
 | 
				
			||||||
 | 
					            border: 1em;
 | 
				
			||||||
 | 
					            background-color: white;
 | 
				
			||||||
 | 
					            width: 40%;
 | 
				
			||||||
 | 
					            height: auto;
 | 
				
			||||||
 | 
					            margin-left: auto;
 | 
				
			||||||
 | 
					            margin-right: auto;
 | 
				
			||||||
 | 
					            margin-bottom: auto;
 | 
				
			||||||
 | 
					            margin-top: 50px;
 | 
				
			||||||
 | 
					            position: relative;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .passwordtext {
 | 
					        .passwordtext {
 | 
				
			||||||
@@ -67,7 +75,13 @@
 | 
				
			|||||||
            margin-left: 5%;
 | 
					            margin-left: 5%;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .password-input {
 | 
				
			||||||
 | 
					            margin-top: 0px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .rulestext {
 | 
					        .rulestext {
 | 
				
			||||||
 | 
					            width: 95%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
            display: inline-block;
 | 
					            display: inline-block;
 | 
				
			||||||
            text-align: left;
 | 
					            text-align: left;
 | 
				
			||||||
            text-justify: none;
 | 
					            text-justify: none;
 | 
				
			||||||
@@ -101,17 +115,18 @@
 | 
				
			|||||||
</head>
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="imgcontainer">
 | 
				
			||||||
 | 
					    <img src="/wwwassets/the_logo.png" alt="OpenWifi">
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()">
 | 
					<form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()">
 | 
				
			||||||
<input type="hidden" id="custId" name="id" value="${UUID}">
 | 
					<input type="hidden" id="custId" name="id" value="${UUID}">
 | 
				
			||||||
<div class="grid-container">
 | 
					<div class="grid-container">
 | 
				
			||||||
 | 
					    <h2>Reset Password</h2>
 | 
				
			||||||
        <div class="imgcontainer">
 | 
					 | 
				
			||||||
            <img src="/wwwassets/open-wifi.svg" alt="Logo" class="logo">
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="passwordlabel">
 | 
					    <div class="passwordlabel">
 | 
				
			||||||
        <label class="passwordtext" for="password1" ><b>New Password</b></label>
 | 
					        <label class="passwordtext" for="password1" ><b>New Password</b></label>
 | 
				
			||||||
        <input id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required>
 | 
					        <input className="password-input" id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="passwordlabel">
 | 
					    <div class="passwordlabel">
 | 
				
			||||||
        <label class="passwordtext" for="password2"><b>Retype Password</b></label>
 | 
					        <label class="passwordtext" for="password2"><b>Retype Password</b></label>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,107 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html lang="en">
 | 
					<html lang="en">
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
    <title>Reset Password Failed</title>
 | 
					    <style>
 | 
				
			||||||
 | 
					        body {font-family: Arial, Helvetica, sans-serif;}
 | 
				
			||||||
 | 
					        form {border: 3px solid #f1f1f1;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        input[type=text], input[type=password] {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            padding: 12px 20px;
 | 
				
			||||||
 | 
					            margin: 8px 0;
 | 
				
			||||||
 | 
					            display: inline-block;
 | 
				
			||||||
 | 
					            border: 1px solid #ccc;
 | 
				
			||||||
 | 
					            box-sizing: border-box;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        button {
 | 
				
			||||||
 | 
					            background-color: #04AA6D;
 | 
				
			||||||
 | 
					            color: white;
 | 
				
			||||||
 | 
					            padding: 14px 20px;
 | 
				
			||||||
 | 
					            margin: 8px 0;
 | 
				
			||||||
 | 
					            border: none;
 | 
				
			||||||
 | 
					            cursor: pointer;
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        button:hover {
 | 
				
			||||||
 | 
					            opacity: 0.8;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .imgcontainer {
 | 
				
			||||||
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            margin-top: 5%;
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        img.avatar {
 | 
				
			||||||
 | 
					            width: 40%;
 | 
				
			||||||
 | 
					            border-radius: 50%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .container {
 | 
				
			||||||
 | 
					            padding: 16px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-card {
 | 
				
			||||||
 | 
					            padding: 30px;
 | 
				
			||||||
 | 
					            box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            width: 50%;
 | 
				
			||||||
 | 
					            border: 1em;
 | 
				
			||||||
 | 
					            background-color: white;
 | 
				
			||||||
 | 
					            width: 40%;
 | 
				
			||||||
 | 
					            height: auto;
 | 
				
			||||||
 | 
					            margin-left: auto;
 | 
				
			||||||
 | 
					            margin-right: auto;
 | 
				
			||||||
 | 
					            margin-bottom: auto;
 | 
				
			||||||
 | 
					            margin-top: 50px;
 | 
				
			||||||
 | 
					            position: relative;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-list {
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .info-title {
 | 
				
			||||||
 | 
					            padding-bottom: 20px;
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            margin: auto;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .body {
 | 
				
			||||||
 | 
					            background-color: #ebedef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        span.password1 {
 | 
				
			||||||
 | 
					            float: right;
 | 
				
			||||||
 | 
					            padding-top: 16px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Change styles for span and cancel button on extra small screens */
 | 
				
			||||||
 | 
					        @media screen and (max-width: 300px) {
 | 
				
			||||||
 | 
					            span.password1 {
 | 
				
			||||||
 | 
					                display: block;
 | 
				
			||||||
 | 
					                float: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .cancelbtn {
 | 
				
			||||||
 | 
					                width: 100%;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body class="body">
 | 
				
			||||||
    <h1>Password reset failed...</h1>
 | 
					
 | 
				
			||||||
 | 
					<div class="imgcontainer">
 | 
				
			||||||
 | 
					    <img src="/wwwassets/the_logo.png" alt="OpenWifi">
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="info-card">
 | 
				
			||||||
 | 
					    <h1 class="info-title">Reset Password Failed</h1>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <h3>ID</h3>
 | 
					        <h3>ID</h3>
 | 
				
			||||||
        <b>${UUID}</b>
 | 
					        <b>${UUID}</b>
 | 
				
			||||||
@@ -14,5 +110,7 @@
 | 
				
			|||||||
        <h3>Error</h3>
 | 
					        <h3>Error</h3>
 | 
				
			||||||
        <b>${ERROR_TEXT}</b>
 | 
					        <b>${ERROR_TEXT}</b>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
@@ -62,8 +62,9 @@
 | 
				
			|||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <div class="imgcontainer">
 | 
					    <div class="imgcontainer">
 | 
				
			||||||
      <img src="/wwwassets/avatar.jpg" alt="Avatar" class="avatar">
 | 
					      <img src="/wwwassets/the_logo.png" alt="Avatar" class="avatar">
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <h1>Password was successfully reset</h1>
 | 
					    <h1>Password was successfully reset</h1>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <h3>Thank you ${USERNAME} for resetting your password.</h3>
 | 
					        <h3>Thank you ${USERNAME} for resetting your password.</h3>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								wwwassets/the_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wwwassets/the_logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.8 KiB  | 
		Reference in New Issue
	
	Block a user