mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 02:37:56 +00:00 
			
		
		
		
	Compare commits
	
		
			63 Commits
		
	
	
		
			v2.6.0-RC1
			...
			v2.7.0-RC1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 4b1fbf055f | ||
|   | 8b5c9dd5e9 | ||
|   | 02a315ab0d | ||
|   | 1e4d9ea4e8 | ||
|   | 0b1d7e39eb | ||
|   | af190e9967 | ||
|   | 80d3dfb89f | ||
|   | 62c6b119c9 | ||
|   | 4ea8aa9958 | ||
|   | 6a30353b3a | ||
|   | b355b41d4f | ||
|   | 19b2afb469 | ||
|   | 7d65da3abc | ||
|   | c25059e2aa | ||
|   | 122a73f35e | ||
|   | a454b56c7a | ||
|   | ae82160c7f | ||
|   | 4d73bbd605 | ||
|   | 13bec235a1 | ||
|   | e6c196cd67 | ||
|   | 6d9a1cac09 | ||
|   | 55a43ed40d | ||
|   | 3a230e4250 | ||
|   | 0a6ee4ea47 | ||
|   | a430ad7e71 | ||
|   | d1c13ad2dd | ||
|   | b837e41569 | ||
|   | 5e39987e36 | ||
|   | 890eb7311a | ||
|   | fc509adf01 | ||
|   | 767331f575 | ||
|   | d26ef6eeba | ||
|   | 8c672f058f | ||
|   | 448563ab06 | ||
|   | 2a22a35e58 | ||
|   | e745d4efe7 | ||
|   | 701e0b50ff | ||
|   | df082a969e | ||
|   | 5e1937ec4f | ||
|   | e679dc7458 | ||
|   | 7e1a962b57 | ||
|   | 8ad2e12f12 | ||
|   | 23d16e619a | ||
|   | 760cad9a14 | ||
|   | 94997a1f9f | ||
|   | 9060fef03d | ||
|   | 2f8eb90c5a | ||
|   | c0d0435efa | ||
|   | 6942de0475 | ||
|   | cce2528ec4 | ||
|   | 3be0fd45d9 | ||
|   | 8b1a80ce09 | ||
|   | 5e12f00558 | ||
|   | 1d534cb974 | ||
|   | a7e9c96f8d | ||
|   | cb3f7a0872 | ||
|   | 6ad434c02f | ||
|   | 62e3ada15c | ||
|   | 2beef2daba | ||
|   | 4b131465fb | ||
|   | cafc243e55 | ||
|   | 5c44134f9d | ||
|   | 8ed86d3582 | 
							
								
								
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,4 +17,10 @@ jobs: | |||||||
|     steps: |     steps: | ||||||
|       - run: | |       - run: | | ||||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') |           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||||
|           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG" |  | ||||||
|  |           if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then | ||||||
|  |             echo "PR branch is $PR_BRANCH_TAG, deleting Docker image" | ||||||
|  |             curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG" | ||||||
|  |           else | ||||||
|  |             echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image" | ||||||
|  |           fi | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| cmake_minimum_required(VERSION 3.13) | cmake_minimum_required(VERSION 3.13) | ||||||
| project(owsec VERSION 2.6.0) | project(owsec VERSION 2.7.0) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 17) | set(CMAKE_CXX_STANDARD 17) | ||||||
|  |  | ||||||
| @@ -124,7 +124,7 @@ add_executable( owsec | |||||||
|         src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h |         src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h | ||||||
|         src/storage/orm_avatar.cpp src/storage/orm_avatar.h |         src/storage/orm_avatar.cpp src/storage/orm_avatar.h | ||||||
|         src/SpecialUserHelpers.h |         src/SpecialUserHelpers.h | ||||||
|         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h) |         src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h) | ||||||
|  |  | ||||||
| if(NOT SMALL_BUILD) | if(NOT SMALL_BUILD) | ||||||
|     target_link_libraries(owsec PUBLIC |     target_link_libraries(owsec PUBLIC | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,4 +1,11 @@ | |||||||
| FROM alpine:3.15 AS build-base | ARG ALPINE_VERSION=3.16.2 | ||||||
|  | ARG POCO_VERSION=poco-tip-v1 | ||||||
|  | ARG FMTLIB_VERSION=9.0.0 | ||||||
|  | ARG CPPKAFKA_VERSION=tip-v1 | ||||||
|  | ARG JSON_VALIDATOR_VERSION=2.1.0 | ||||||
|  | ARG AWS_SDK_VERSION=1.9.315 | ||||||
|  |  | ||||||
|  | FROM alpine:$ALPINE_VERSION AS build-base | ||||||
|  |  | ||||||
| RUN apk add --update --no-cache \ | RUN apk add --update --no-cache \ | ||||||
|     make cmake g++ git \ |     make cmake g++ git \ | ||||||
| @@ -9,8 +16,10 @@ RUN apk add --update --no-cache \ | |||||||
|  |  | ||||||
| FROM build-base AS poco-build | FROM build-base AS poco-build | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json | ARG POCO_VERSION | ||||||
| RUN git clone https://github.com/stephb9959/poco /poco |  | ||||||
|  | ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json | ||||||
|  | RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco | ||||||
|  |  | ||||||
| WORKDIR /poco | WORKDIR /poco | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -21,8 +30,10 @@ RUN cmake --build . --target install | |||||||
|  |  | ||||||
| FROM build-base AS fmtlib-build | FROM build-base AS fmtlib-build | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json | ARG FMTLIB_VERSION | ||||||
| RUN git clone https://github.com/fmtlib/fmt /fmtlib |  | ||||||
|  | ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json | ||||||
|  | RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib | ||||||
|  |  | ||||||
| WORKDIR /fmtlib | WORKDIR /fmtlib | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -33,8 +44,10 @@ RUN make install | |||||||
|  |  | ||||||
| FROM build-base AS cppkafka-build | FROM build-base AS cppkafka-build | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json | ARG CPPKAFKA_VERSION | ||||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka |  | ||||||
|  | ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json | ||||||
|  | RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka | ||||||
|  |  | ||||||
| WORKDIR /cppkafka | WORKDIR /cppkafka | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -45,8 +58,10 @@ RUN cmake --build . --target install | |||||||
|  |  | ||||||
| FROM build-base AS json-schema-validator-build | FROM build-base AS json-schema-validator-build | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json | ARG JSON_VALIDATOR_VERSION | ||||||
| RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator |  | ||||||
|  | ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json | ||||||
|  | RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator | ||||||
|  |  | ||||||
| WORKDIR /json-schema-validator | WORKDIR /json-schema-validator | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -57,8 +72,10 @@ RUN make install | |||||||
|  |  | ||||||
| FROM build-base AS aws-sdk-cpp-build | FROM build-base AS aws-sdk-cpp-build | ||||||
|  |  | ||||||
| ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json | ARG AWS_SDK_VERSION | ||||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp |  | ||||||
|  | ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json | ||||||
|  | RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp | ||||||
|  |  | ||||||
| WORKDIR /aws-sdk-cpp | WORKDIR /aws-sdk-cpp | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -97,7 +114,7 @@ RUN cmake .. \ | |||||||
|           -DBUILD_SHARED_LIBS=ON |           -DBUILD_SHARED_LIBS=ON | ||||||
| RUN cmake --build . --config Release -j8 | RUN cmake --build . --config Release -j8 | ||||||
|  |  | ||||||
| FROM alpine:3.15 | FROM alpine:$ALPINE_VERSION | ||||||
|  |  | ||||||
| ENV OWSEC_USER=owsec \ | ENV OWSEC_USER=owsec \ | ||||||
|     OWSEC_ROOT=/owsec-data \ |     OWSEC_ROOT=/owsec-data \ | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								OPERATOR.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | # Operator Support | ||||||
|  | In order to support multiple tenants and operators, you must prepare the security service to serve | ||||||
|  | customized e-mails and messages. | ||||||
|  |  | ||||||
|  | ## Structure for `templates` | ||||||
|  | Any file in the root of the directory will be used as defaults. The following files must be present: | ||||||
|  | - email_invitation.html/txt : This email message will be sent to a newly added user.  | ||||||
|  | - email_verification.html/txt : This email is sent when an email verification is required. | ||||||
|  | - password_reset.html/txt : This is sent when a pasword reset is requested. | ||||||
|  | - verification_code.html/txt : This is used during MFA when email based. | ||||||
|  | - signup_verification.html/txt : This email is send to a new subscriber who signed up for service. | ||||||
|  | - sub_email_verification.html/txt : This is sent to a subscriber requiring an email verification. | ||||||
|  | - sub_verification_code.html/txt : This is used during MFA when email based for a subscriber. | ||||||
|  | - logo.jpg : The default logo to use in any of these emails. | ||||||
|  |  | ||||||
|  | ## Structure for `wwwassets` | ||||||
|  | Any file in the root of the directory will be used as defaults. The following files must be present: | ||||||
|  | - email_verification_error.html : Used when email verification has failed. | ||||||
|  | - email_verification_success.html : Used when emil verification has succeeded. | ||||||
|  | - invitation_error.html : | ||||||
|  | - invitation_success.html : | ||||||
|  | - password_policy.html : | ||||||
|  | - password_reset.html : | ||||||
|  | - password_reset_success.html : | ||||||
|  | - password_reset_error.html : | ||||||
|  | - signup_verification.html : | ||||||
|  | - signup_verification_error.html : | ||||||
|  | - signup_verification_success.html : | ||||||
|  | - favicon.ico : icon for the application | ||||||
|  | - 404_error.html : your customized 404 page | ||||||
|  | - the_logo : the logo to use. | ||||||
|  |  | ||||||
|  | ## For tenants | ||||||
|  | When creating a tenant/operator, you must create a subdirectory inside each `wwwassets` and `templates` and replicate  | ||||||
|  | all the files that appear at the root level. You need to use the short Operator name (also known as RegistrantId in the API). This means  | ||||||
|  | no spaces, all lowercase characters and numbers. No special characters: 0-9 and a-z.  | ||||||
|  |  | ||||||
| @@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then | |||||||
|     update-ca-certificates |     update-ca-certificates | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; then | if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||||
|   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \ |   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \ | ||||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ |   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \ | ||||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ |   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \ | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,3 @@ | |||||||
| *.swp | *.swp | ||||||
|  | Chart.lock | ||||||
|  | charts/ | ||||||
|   | |||||||
| @@ -5,14 +5,14 @@ name: owsec | |||||||
| version: 0.1.0 | version: 0.1.0 | ||||||
| dependencies: | dependencies: | ||||||
| - name: postgresql | - name: postgresql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 10.9.2 |   version: 10.9.2 | ||||||
|   condition: postgresql.enabled |   condition: postgresql.enabled | ||||||
| - name: mysql | - name: mysql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 8.8.3 |   version: 8.8.3 | ||||||
|   condition: mysql.enabled |   condition: mysql.enabled | ||||||
| - name: mariadb | - name: mariadb | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 9.4.2 |   version: 9.4.2 | ||||||
|   condition: mariadb.enabled |   condition: mariadb.enabled | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| {{- $root := . -}} | {{- $root := . -}} | ||||||
|  | {{- $storageType := index .Values.configProperties "storage.type" -}} | ||||||
| --- | --- | ||||||
| apiVersion: apps/v1 | apiVersion: apps/v1 | ||||||
| kind: Deployment | kind: Deployment | ||||||
| @@ -46,6 +47,39 @@ spec: | |||||||
|             - -timeout |             - -timeout | ||||||
|             - 600s |             - 600s | ||||||
|  |  | ||||||
|  | {{- if eq $storageType "postgresql" }} | ||||||
|  |         - name: wait-postgres | ||||||
|  |           image: "{{ .Values.images.owsec.repository }}:{{ .Values.images.owsec.tag }}" | ||||||
|  |           imagePullPolicy: {{ .Values.images.owsec.pullPolicy }} | ||||||
|  |           command: | ||||||
|  |             - /wait-for-postgres.sh | ||||||
|  |             - {{ index .Values.configProperties "storage.type.postgresql.host" }} | ||||||
|  |             - echo | ||||||
|  |             - "PostgreSQL is ready" | ||||||
|  |           env: | ||||||
|  |             - name: KUBERNETES_DEPLOYED | ||||||
|  |               value: "{{ now }}" | ||||||
|  |           {{- range $key, $value := .Values.public_env_variables }} | ||||||
|  |             - name: {{ $key }} | ||||||
|  |               value: {{ $value | quote }} | ||||||
|  |           {{- end }} | ||||||
|  |           {{- range $key, $value := .Values.secret_env_variables }} | ||||||
|  |             - name: {{ $key }} | ||||||
|  |               valueFrom: | ||||||
|  |                 secretKeyRef: | ||||||
|  |                   name: {{ include "owsec.fullname" $root }}-env | ||||||
|  |                   key: {{ $key }} | ||||||
|  |           {{- end }} | ||||||
|  |           volumeMounts: | ||||||
|  |           {{- range .Values.volumes.owsec }} | ||||||
|  |           - name: {{ .name }} | ||||||
|  |             mountPath: {{ .mountPath }} | ||||||
|  |             {{- if .subPath }} | ||||||
|  |             subPath: {{ .subPath }} | ||||||
|  |             {{- end }} | ||||||
|  |           {{- end }} | ||||||
|  | {{- end }} | ||||||
|  |  | ||||||
|       containers: |       containers: | ||||||
|  |  | ||||||
|         - name: owsec |         - name: owsec | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ fullnameOverride: "" | |||||||
| images: | images: | ||||||
|   owsec: |   owsec: | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||||
|     tag: main |     tag: v2.7.0-RC1 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include "ActionLinkManager.h" | #include "ActionLinkManager.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  | #include "MessagingTemplates.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -24,6 +25,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void ActionLinkManager::run() { |     void ActionLinkManager::run() { | ||||||
|         Running_ = true ; |         Running_ = true ; | ||||||
|  |         Utils::SetThreadName("action-mgr"); | ||||||
|  |  | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(2000); |             Poco::Thread::trySleep(2000); | ||||||
| @@ -52,11 +54,15 @@ namespace OpenWifi { | |||||||
|                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { |                             i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) { | ||||||
|                     StorageService()->ActionLinksDB().CancelAction(i.id); |                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||||
|                     continue; |                     continue; | ||||||
|  |                 } else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) && | ||||||
|  |                         (OpenWifi::Now()-i.created)>(24*60*60)) { | ||||||
|  |                     StorageService()->ActionLinksDB().CancelAction(i.id); | ||||||
|  |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 switch(i.action) { |                 switch(i.action) { | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { |                     case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: { | ||||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { |                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) { | ||||||
|                                 Logger().information(fmt::format("Send password reset link to {}",UInfo.email)); |                                 Logger().information(fmt::format("Send password reset link to {}",UInfo.email)); | ||||||
|                             } |                             } | ||||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
| @@ -64,15 +70,24 @@ namespace OpenWifi { | |||||||
|                         break; |                         break; | ||||||
|  |  | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: { |                     case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: { | ||||||
|                             if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { |                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) { | ||||||
|                                 Logger().information(fmt::format("Send email verification link to {}",UInfo.email)); |                                 Logger().information(fmt::format("Send email verification link to {}",UInfo.email)); | ||||||
|                             } |                             } | ||||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|                         } |                         } | ||||||
|                         break; |                         break; | ||||||
|  |  | ||||||
|  |                     case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: { | ||||||
|  |                             if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) { | ||||||
|  |                                 Logger().information(fmt::format("Send new subscriber email invitation link to {}",UInfo.email)); | ||||||
|  |                             } | ||||||
|  |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|  |                         } | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: { |                     case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: { | ||||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { |                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||||
|  |                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) { | ||||||
|                                 Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email)); |                                 Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email)); | ||||||
|                             } |                             } | ||||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
| @@ -80,7 +95,8 @@ namespace OpenWifi { | |||||||
|                         break; |                         break; | ||||||
|  |  | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: { |                     case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: { | ||||||
|                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { |                             auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||||
|  |                             if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||||
|                                 Logger().information(fmt::format("Send subscriber email verification link to {}",UInfo.email)); |                                 Logger().information(fmt::format("Send subscriber email verification link to {}",UInfo.email)); | ||||||
|                             } |                             } | ||||||
|                             StorageService()->ActionLinksDB().SentAction(i.id); |                             StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
| @@ -88,7 +104,8 @@ namespace OpenWifi { | |||||||
|                         break; |                         break; | ||||||
|  |  | ||||||
|                     case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: { |                     case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: { | ||||||
|                         if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::SIGNUP_VERIFICATION)) { |                         auto Signup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||||
|  |                         if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) { | ||||||
|                             Logger().information(fmt::format("Send new subscriber email verification link to {}",UInfo.email)); |                             Logger().information(fmt::format("Send new subscriber email verification link to {}",UInfo.email)); | ||||||
|                         } |                         } | ||||||
|                         StorageService()->ActionLinksDB().SentAction(i.id); |                         StorageService()->ActionLinksDB().SentAction(i.id); | ||||||
|   | |||||||
| @@ -12,14 +12,6 @@ namespace OpenWifi { | |||||||
|     class ActionLinkManager : public SubSystemServer, Poco::Runnable { |     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
| /*        enum Actions { |  | ||||||
|             FORGOT_PASSWORD, |  | ||||||
|             VERIFY_EMAIL, |  | ||||||
|             SUB_FORGOT_PASSWORD, |  | ||||||
|             SUB_VERIFY_EMAIL, |  | ||||||
|             SUB_SIGNUP |  | ||||||
|         }; |  | ||||||
| */ |  | ||||||
|         static ActionLinkManager * instance() { |         static ActionLinkManager * instance() { | ||||||
|             static auto instance_ = new ActionLinkManager; |             static auto instance_ = new ActionLinkManager; | ||||||
|             return instance_; |             return instance_; | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "MFAServer.h" | #include "MFAServer.h" | ||||||
|  | #include "MessagingTemplates.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -33,7 +34,6 @@ namespace OpenWifi { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	int AuthService::AccessTypeToInt(ACCESS_TYPE T) { | 	int AuthService::AccessTypeToInt(ACCESS_TYPE T) { | ||||||
| 		switch (T) { | 		switch (T) { | ||||||
| 		case USERNAME: return 1; | 		case USERNAME: return 1; | ||||||
| @@ -51,13 +51,13 @@ namespace OpenWifi { | |||||||
|         RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600); |         RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600); | ||||||
|         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); |         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); | ||||||
|  |  | ||||||
|         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); |         AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||||
|         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); |         PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1); |         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1); | ||||||
|  |  | ||||||
|         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1); |         SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1); | ||||||
|         SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html"); |         SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html"); | ||||||
|         SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html"); |         SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html"); | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| @@ -514,7 +514,6 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             return SUCCESS; |             return SUCCESS; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return INVALID_CREDENTIALS; |         return INVALID_CREDENTIALS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -564,29 +563,62 @@ namespace OpenWifi { | |||||||
|         return INVALID_CREDENTIALS; |         return INVALID_CREDENTIALS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { |     bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) { | ||||||
|  |         auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp,":"); | ||||||
|  |         if(UInfo.userinfo.signingUp.empty() || OperatorParts.count()!=2) { | ||||||
|  |             MessageAttributes Attrs; | ||||||
|  |             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||||
|  |             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||||
|  |             Attrs[SUBJECT] = "Login validation code"; | ||||||
|  |             Attrs[CHALLENGE_CODE] = Challenge; | ||||||
|  |             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs); | ||||||
|  |         } else { | ||||||
|  |             MessageAttributes Attrs; | ||||||
|  |             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||||
|  |             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||||
|  |             Attrs[SUBJECT] = "Login validation code"; | ||||||
|  |             Attrs[CHALLENGE_CODE] = Challenge; | ||||||
|  |             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) { | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { |         if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) { | ||||||
|             switch (Reason) { |             switch (Reason) { | ||||||
|  |  | ||||||
|                 case FORGOT_PASSWORD: { |                 case MessagingTemplates::FORGOT_PASSWORD: { | ||||||
|                         MessageAttributes Attrs; |                         MessageAttributes Attrs; | ||||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; |                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                         Attrs[LOGO] = GetLogoAssetURI(); |                         Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                         Attrs[SUBJECT] = "Password reset link"; |                         Attrs[SUBJECT] = "Password reset link"; | ||||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; |                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); |                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId ; | ||||||
|  |                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs); | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|                 case EMAIL_VERIFICATION: { |                 case MessagingTemplates::EMAIL_VERIFICATION: { | ||||||
|                         MessageAttributes Attrs; |                         MessageAttributes Attrs; | ||||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; |                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                         Attrs[LOGO] = GetLogoAssetURI(); |                         Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                         Attrs[SUBJECT] = "e-mail Address Verification"; |                         Attrs[SUBJECT] = "e-mail Address Verification"; | ||||||
|                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; |                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |                         Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ; | ||||||
|  |                         SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs); | ||||||
|  |                         UInfo.waitingForEmailCheck = true; | ||||||
|  |                     } | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 case MessagingTemplates::EMAIL_INVITATION: { | ||||||
|  |                     MessageAttributes Attrs; | ||||||
|  |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|  |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|  |                     Attrs[SUBJECT] = "e-mail Invitation"; | ||||||
|  |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_invitation&id=" + LinkId ; | ||||||
|  |                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_invitation&id=" + LinkId ; | ||||||
|  |                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs); | ||||||
|                     UInfo.waitingForEmailCheck = true; |                     UInfo.waitingForEmailCheck = true; | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
| @@ -599,40 +631,43 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { |     bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) { | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) { |         if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) { | ||||||
|             switch (Reason) { |             switch (Reason) { | ||||||
|  |  | ||||||
|                 case FORGOT_PASSWORD: { |                 case MessagingTemplates::SUB_FORGOT_PASSWORD: { | ||||||
|                     MessageAttributes Attrs; |                     MessageAttributes Attrs; | ||||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                     Attrs[LOGO] = GetLogoAssetURI(); |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                     Attrs[SUBJECT] = "Password reset link"; |                     Attrs[SUBJECT] = "Password reset link"; | ||||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); |                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ; | ||||||
|  |                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|                 case EMAIL_VERIFICATION: { |                 case MessagingTemplates::SUB_EMAIL_VERIFICATION: { | ||||||
|                     MessageAttributes Attrs; |                     MessageAttributes Attrs; | ||||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                     Attrs[LOGO] = GetLogoAssetURI(); |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                     Attrs[SUBJECT] = "e-mail Address Verification"; |                     Attrs[SUBJECT] = "e-mail Address Verification"; | ||||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_email_verification&id=" + LinkId ; | ||||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ; | ||||||
|  |                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs); | ||||||
|                     UInfo.waitingForEmailCheck = true; |                     UInfo.waitingForEmailCheck = true; | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|                 case SIGNUP_VERIFICATION: { |                 case MessagingTemplates::SIGNUP_VERIFICATION: { | ||||||
|                     MessageAttributes Attrs; |                     MessageAttributes Attrs; | ||||||
|                     Attrs[RECIPIENT_EMAIL] = UInfo.email; |                     Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                     Attrs[LOGO] = GetLogoAssetURI(); |                     Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                     Attrs[SUBJECT] = "Signup e-mail Address Verification"; |                     Attrs[SUBJECT] = "Signup e-mail Address Verification"; | ||||||
|                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ; |                     Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ; | ||||||
|                     SMTPMailerService()->SendMessage(UInfo.email, "signup_verification.txt", Attrs); |                     Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ; | ||||||
|  |                     SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs); | ||||||
|                     UInfo.waitingForEmailCheck = true; |                     UInfo.waitingForEmailCheck = true; | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  | #include "MessagingTemplates.h" | ||||||
|  |  | ||||||
| namespace OpenWifi{ | namespace OpenWifi{ | ||||||
|  |  | ||||||
| @@ -36,12 +37,6 @@ namespace OpenWifi{ | |||||||
|             CUSTOM |             CUSTOM | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         enum EMAIL_REASON { |  | ||||||
|             FORGOT_PASSWORD, |  | ||||||
|             EMAIL_VERIFICATION, |  | ||||||
|             SIGNUP_VERIFICATION |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         static ACCESS_TYPE IntToAccessType(int C); |         static ACCESS_TYPE IntToAccessType(int C); | ||||||
|         static int AccessTypeToInt(ACCESS_TYPE T); |         static int AccessTypeToInt(ACCESS_TYPE T); | ||||||
|  |  | ||||||
| @@ -90,10 +85,12 @@ namespace OpenWifi{ | |||||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); |         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); |         [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason); | ||||||
|         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName); | ||||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); |         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|  |  | ||||||
|  |         [[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code); | ||||||
|  |  | ||||||
|         bool DeleteUserFromCache(const std::string &UserName); |         bool DeleteUserFromCache(const std::string &UserName); | ||||||
|         bool DeleteSubUserFromCache(const std::string &UserName); |         bool DeleteSubUserFromCache(const std::string &UserName); | ||||||
|         void RevokeToken(std::string & Token); |         void RevokeToken(std::string & Token); | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
| //	Arilia Wireless Inc. | //	Arilia Wireless Inc. | ||||||
| // | // | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Poco/Util/Application.h" | #include "Poco/Util/Application.h" | ||||||
| #include "Poco/Util/Option.h" | #include "Poco/Util/Option.h" | ||||||
| #include "Poco/Environment.h" | #include "Poco/Environment.h" | ||||||
|   | |||||||
| @@ -44,12 +44,7 @@ namespace OpenWifi { | |||||||
|             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; |             std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen."; | ||||||
|             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); |             return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message); | ||||||
|         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { |         } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||||
|             MessageAttributes Attrs; |             return AuthService()->SendEmailChallengeCode(UInfo,Challenge); | ||||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; |  | ||||||
|             Attrs[LOGO] = AuthService::GetLogoAssetURI(); |  | ||||||
|             Attrs[SUBJECT] = "Login validation code"; |  | ||||||
|             Attrs[CHALLENGE_CODE] = Challenge; |  | ||||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); |  | ||||||
|         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { |         } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								src/MessagingTemplates.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/MessagingTemplates.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-07-25. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "MessagingTemplates.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  | } // OpenWifi | ||||||
							
								
								
									
										75
									
								
								src/MessagingTemplates.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/MessagingTemplates.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-07-25. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     class MessagingTemplates { | ||||||
|  |     public: | ||||||
|  |         static MessagingTemplates & instance() { | ||||||
|  |             static auto instance = new MessagingTemplates; | ||||||
|  |             return *instance; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         enum EMAIL_REASON { | ||||||
|  |             FORGOT_PASSWORD = 0, | ||||||
|  |             EMAIL_VERIFICATION, | ||||||
|  |             SIGNUP_VERIFICATION, | ||||||
|  |             EMAIL_INVITATION, | ||||||
|  |             VERIFICATION_CODE, | ||||||
|  |             SUB_FORGOT_PASSWORD, | ||||||
|  |             SUB_EMAIL_VERIFICATION, | ||||||
|  |             SUB_VERIFICATION_CODE | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         static std::string AddOperator(const std::string & filename, const std::string &OperatorName) { | ||||||
|  |             if(OperatorName.empty()) | ||||||
|  |                 return "/" + filename; | ||||||
|  |             return "/" + OperatorName + "/" + filename; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") { | ||||||
|  |             switch (r) { | ||||||
|  |                 case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName); | ||||||
|  |                 case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName); | ||||||
|  |                 case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName); | ||||||
|  |                 case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName); | ||||||
|  |                 case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName); | ||||||
|  |                 case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName); | ||||||
|  |                 case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName); | ||||||
|  |                 case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName); | ||||||
|  |                 default: | ||||||
|  |                     return ""; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static std::string Logo(const std::string &OperatorName = "" ) { | ||||||
|  |             return AddOperator("logo.jpg", OperatorName); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         static std::string SubLogo(const std::string &OperatorName = "" ) { | ||||||
|  |             return AddOperator("sub_logo.jpg", OperatorName); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         inline const static std::vector<std::string>  EmailTemplateNames = { | ||||||
|  |                 "password_reset", | ||||||
|  |                 "email_verification", | ||||||
|  |                 "signup_verification", | ||||||
|  |                 "email_invitation", | ||||||
|  |                 "verification_code", | ||||||
|  |                 "sub_password_reset", | ||||||
|  |                 "sub_email_verification", | ||||||
|  |                 "sub_verification_code" | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); } | ||||||
|  |  | ||||||
|  | } // OpenWifi | ||||||
|  |  | ||||||
| @@ -23,8 +23,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             return RequestResetPassword(Link); |             return RequestResetPassword(Link); | ||||||
|  |         else if(Action=="sub_password_reset") | ||||||
|  |             return RequestSubResetPassword(Link); | ||||||
|         else if(Action=="email_verification") |         else if(Action=="email_verification") | ||||||
|             return DoEmailVerification(Link); |             return DoEmailVerification(Link); | ||||||
|  |         else if(Action=="sub_email_verification") | ||||||
|  |             return DoSubEmailVerification(Link); | ||||||
|         else if(Action=="signup_verification") |         else if(Action=="signup_verification") | ||||||
|             return DoNewSubVerification(Link); |             return DoNewSubVerification(Link); | ||||||
|         else |         else | ||||||
| @@ -36,8 +40,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             return CompleteResetPassword(); |             return CompleteResetPassword(); | ||||||
|  |         else if(Action=="sub_password_reset") | ||||||
|  |             return CompleteResetPassword(); | ||||||
|         else if(Action=="signup_completion") |         else if(Action=="signup_completion") | ||||||
|             return CompleteSubVerification(); |             return CompleteSubVerification(); | ||||||
|  |         else if(Action=="email_invitation") | ||||||
|  |             return CompleteEmailInvitation(); | ||||||
|         else |         else | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|     } |     } | ||||||
| @@ -199,10 +207,11 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             //  Send the update to the provisioning service |             //  Send the update to the provisioning service | ||||||
|             Poco::JSON::Object  Body; |             Poco::JSON::Object  Body; | ||||||
|             Body.set("signupUUID", UInfo.signingUp); |             auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":"); | ||||||
|  |             Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]); | ||||||
|             OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup", |             OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup", | ||||||
|                                             { |                                             { | ||||||
|                                                 {"signupUUID", UInfo.signingUp} , |                                                 {"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} , | ||||||
|                                                 {"operation", "emailVerified"} |                                                 {"operation", "emailVerified"} | ||||||
|                                             }, |                                             }, | ||||||
|                                             Body,30000); |                                             Body,30000); | ||||||
| @@ -238,7 +247,8 @@ namespace OpenWifi { | |||||||
|             return SendHTMLFileBack(FormFile, FormVars); |             return SendHTMLFileBack(FormFile, FormVars); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(), UInfo.email)); |         Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(), | ||||||
|  |                                         UInfo.email)); | ||||||
|         UInfo.waitingForEmailCheck = false; |         UInfo.waitingForEmailCheck = false; | ||||||
|         UInfo.validated = true; |         UInfo.validated = true; | ||||||
|         UInfo.lastEmailCheck = OpenWifi::Now(); |         UInfo.lastEmailCheck = OpenWifi::Now(); | ||||||
| @@ -262,4 +272,16 @@ namespace OpenWifi { | |||||||
|         SendHTMLFileBack(FormFile, FormVars); |         SendHTMLFileBack(FormFile, FormVars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_action_links::CompleteEmailInvitation() { | ||||||
|  |         /// TODO: | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,11 +22,14 @@ namespace OpenWifi { | |||||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} |                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; }; |         static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; }; | ||||||
|         void RequestResetPassword(SecurityObjects::ActionLink &Link); |         void RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||||
|  |         void RequestSubResetPassword(SecurityObjects::ActionLink &Link); | ||||||
|         void CompleteResetPassword(); |         void CompleteResetPassword(); | ||||||
|         void CompleteSubVerification(); |         void CompleteSubVerification(); | ||||||
|         void DoEmailVerification(SecurityObjects::ActionLink &Link); |         void DoEmailVerification(SecurityObjects::ActionLink &Link); | ||||||
|  |         void DoSubEmailVerification(SecurityObjects::ActionLink &Link); | ||||||
|         void DoReturnA404(); |         void DoReturnA404(); | ||||||
|         void DoNewSubVerification(SecurityObjects::ActionLink &Link); |         void DoNewSubVerification(SecurityObjects::ActionLink &Link); | ||||||
|  |         void CompleteEmailInvitation(); | ||||||
|  |  | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
|         void DoPost() final; |         void DoPost() final; | ||||||
|   | |||||||
| @@ -29,7 +29,8 @@ | |||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, |     Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, | ||||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { |                                                             Poco::Logger & L, RESTAPI_GenericServer & S, | ||||||
|  |                                                             uint64_t TransactionId) { | ||||||
|         return RESTAPI_Router< |         return RESTAPI_Router< | ||||||
|             RESTAPI_oauth2_handler, |             RESTAPI_oauth2_handler, | ||||||
|             RESTAPI_user_handler, |             RESTAPI_user_handler, | ||||||
|   | |||||||
| @@ -13,8 +13,9 @@ namespace OpenWifi { | |||||||
|         auto UserName = GetParameter("email"); |         auto UserName = GetParameter("email"); | ||||||
|         auto signupUUID = GetParameter("signupUUID"); |         auto signupUUID = GetParameter("signupUUID"); | ||||||
|         auto owner = GetParameter("owner"); |         auto owner = GetParameter("owner"); | ||||||
|         if(UserName.empty() || signupUUID.empty() || owner.empty()) { |         auto operatorName = GetParameter("operatorName"); | ||||||
|             Logger().error("Signup requires: email, signupUUID, and owner."); |         if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) { | ||||||
|  |             Logger().error("Signup requires: email, signupUUID, operatorName, and owner."); | ||||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); |             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -37,7 +38,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewSub; |         SecurityObjects::UserInfo   NewSub; | ||||||
|         NewSub.signingUp = signupUUID; |         NewSub.signingUp = operatorName + ":" + signupUUID; | ||||||
|         NewSub.waitingForEmailCheck = true; |         NewSub.waitingForEmailCheck = true; | ||||||
|         NewSub.name = UserName; |         NewSub.name = UserName; | ||||||
|         NewSub.modified = OpenWifi::Now(); |         NewSub.modified = OpenWifi::Now(); | ||||||
|   | |||||||
| @@ -12,6 +12,10 @@ namespace OpenWifi { | |||||||
|     void OpenWifi::RESTAPI_sms_handler::DoPost() { |     void OpenWifi::RESTAPI_sms_handler::DoPost() { | ||||||
|         const auto &Obj = ParsedBody_; |         const auto &Obj = ParsedBody_; | ||||||
|  |  | ||||||
|  |         if(!SMSSender()->Enabled()) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         std::string Arg; |         std::string Arg; | ||||||
|         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { |         if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) { | ||||||
|             auto Number = Obj->get("to").toString(); |             auto Number = Obj->get("to").toString(); | ||||||
|   | |||||||
| @@ -76,12 +76,21 @@ namespace OpenWifi { | |||||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); |                         return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  |                     if(!SMSSender()->Enabled()) { | ||||||
|  |                         return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                     if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) { |                     if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) { | ||||||
|                         return OK(); |                         return OK(); | ||||||
|                     } else { |                     } else { | ||||||
|                         return InternalError(RESTAPI::Errors::SMSTryLater); |                         return InternalError(RESTAPI::Errors::SMSTryLater); | ||||||
|                     } |                     } | ||||||
|                 } else if (GetBoolParameter("completeValidation", false)) { |                 } else if (GetBoolParameter("completeValidation", false)) { | ||||||
|  |  | ||||||
|  |                     if(!SMSSender()->Enabled()) { | ||||||
|  |                         return BadRequest(RESTAPI::Errors::SMSMFANotEnabled); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                     auto ChallengeCode = GetParameter("challengeCode", ""); |                     auto ChallengeCode = GetParameter("challengeCode", ""); | ||||||
|                     if (ChallengeCode.empty()) { |                     if (ChallengeCode.empty()) { | ||||||
|                         return BadRequest(RESTAPI::Errors::SMSMissingChallenge); |                         return BadRequest(RESTAPI::Errors::SMSMissingChallenge); | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         auto Reset = GetBoolParameter("reset",false); |         auto Reset = GetBoolParameter("reset",false); | ||||||
|         std::string QRCode; |         std::string QRCode; | ||||||
|  |  | ||||||
|         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { |         if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) { | ||||||
|             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); |             return SendFileContent(QRCode, "image/svg+xml","qrcode.svg"); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -538,8 +538,8 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|  |  | ||||||
|     void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { |     void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj,"timestamp",timestamp); |         field_to_json(Obj,"timestamp",timestamp); | ||||||
|         field_to_json(Obj,"stationId",stationId); |         field_to_json(Obj,"station_id",station_id); | ||||||
|         field_to_json(Obj,"bssId",bssId); |         field_to_json(Obj,"bssid",bssid); | ||||||
|         field_to_json(Obj,"ssid",ssid); |         field_to_json(Obj,"ssid",ssid); | ||||||
|         field_to_json(Obj,"rssi",rssi); |         field_to_json(Obj,"rssi",rssi); | ||||||
|         field_to_json(Obj,"rx_bitrate",rx_bitrate); |         field_to_json(Obj,"rx_bitrate",rx_bitrate); | ||||||
| @@ -573,13 +573,14 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|         field_to_json(Obj,"connected",connected); |         field_to_json(Obj,"connected",connected); | ||||||
|         field_to_json(Obj,"inactive",inactive); |         field_to_json(Obj,"inactive",inactive); | ||||||
|         field_to_json(Obj,"tx_retries",tx_retries); |         field_to_json(Obj,"tx_retries",tx_retries); | ||||||
|  |         field_to_json(Obj,"venue_id",venue_id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj,"timestamp",timestamp); |             field_from_json(Obj,"timestamp",timestamp); | ||||||
|             field_from_json(Obj,"stationId",stationId); |             field_from_json(Obj,"station_id",station_id); | ||||||
|             field_from_json(Obj,"bssId",bssId); |             field_from_json(Obj,"bssid",bssid); | ||||||
|             field_from_json(Obj,"ssid",ssid); |             field_from_json(Obj,"ssid",ssid); | ||||||
|             field_from_json(Obj,"rssi",rssi); |             field_from_json(Obj,"rssi",rssi); | ||||||
|             field_from_json(Obj,"rx_bitrate",rx_bitrate); |             field_from_json(Obj,"rx_bitrate",rx_bitrate); | ||||||
| @@ -613,6 +614,7 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|             field_from_json(Obj,"connected",connected); |             field_from_json(Obj,"connected",connected); | ||||||
|             field_from_json(Obj,"inactive",inactive); |             field_from_json(Obj,"inactive",inactive); | ||||||
|             field_from_json(Obj,"tx_retries",tx_retries); |             field_from_json(Obj,"tx_retries",tx_retries); | ||||||
|  |             field_from_json(Obj,"venue_id",venue_id); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -376,8 +376,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         struct WifiClientHistory { |         struct WifiClientHistory { | ||||||
|             uint64_t        timestamp=OpenWifi::Now(); |             uint64_t        timestamp=OpenWifi::Now(); | ||||||
|             std::string     stationId; |             std::string     station_id; | ||||||
|             std::string     bssId; |             std::string     bssid; | ||||||
|             std::string     ssid; |             std::string     ssid; | ||||||
|             int64_t         rssi=0; |             int64_t         rssi=0; | ||||||
|             uint32_t        rx_bitrate=0; |             uint32_t        rx_bitrate=0; | ||||||
| @@ -411,6 +411,7 @@ namespace OpenWifi { | |||||||
|             uint64_t        connected=0; |             uint64_t        connected=0; | ||||||
|             uint64_t        inactive=0; |             uint64_t        inactive=0; | ||||||
|             uint64_t        tx_retries=0; |             uint64_t        tx_retries=0; | ||||||
|  |             std::string     venue_id; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|   | |||||||
| @@ -3,12 +3,12 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| #include "RESTAPI_CertObjects.h" | #include "RESTAPI_CertObjects.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| using OpenWifi::RESTAPI_utils::field_to_json; | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
| using OpenWifi::RESTAPI_utils::field_from_json; | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi::CertObjects { | ||||||
|     namespace  CertObjects { |  | ||||||
|     void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { |     void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj,"id", id); |         field_to_json(Obj,"id", id); | ||||||
|         field_to_json(Obj,"entity", entity); |         field_to_json(Obj,"entity", entity); | ||||||
| @@ -29,6 +29,7 @@ namespace OpenWifi { | |||||||
|         field_to_json(Obj,"modified", modified); |         field_to_json(Obj,"modified", modified); | ||||||
|         field_to_json(Obj,"revoked", revoked); |         field_to_json(Obj,"revoked", revoked); | ||||||
|         field_to_json(Obj,"revokeCount", revokeCount); |         field_to_json(Obj,"revokeCount", revokeCount); | ||||||
|  |         field_to_json(Obj,"synched", synched); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -52,6 +53,7 @@ namespace OpenWifi { | |||||||
|             field_from_json(Obj,"modified", modified); |             field_from_json(Obj,"modified", modified); | ||||||
|             field_from_json(Obj,"revoked", revoked); |             field_from_json(Obj,"revoked", revoked); | ||||||
|             field_from_json(Obj,"revokeCount", revokeCount); |             field_from_json(Obj,"revokeCount", revokeCount); | ||||||
|  |             field_from_json(Obj,"synched", synched); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|         } |         } | ||||||
| @@ -174,5 +176,33 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "year", year); | ||||||
|  |         field_to_json(Obj, "activeCerts", activeCerts); | ||||||
|  |         field_to_json(Obj, "revokedCerts", revokedCerts); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"snapshot", snapshot); | ||||||
|  |         field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts); | ||||||
|  |         field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts); | ||||||
|  |         field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization); | ||||||
|  |         field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization); | ||||||
|  |         field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors); | ||||||
|  |         field_to_json(Obj,"deviceTypes", deviceTypes); | ||||||
|  |         field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts); | ||||||
|  |         field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::reset() { | ||||||
|  |         snapshot=0; | ||||||
|  |         numberOfRevokedCerts = numberOfIssuedCerts = 0; | ||||||
|  |         activeCertsPerOrganization.clear(); | ||||||
|  |         revokedCertsPerOrganization.clear(); | ||||||
|  |         numberOfRedirectors.clear(); | ||||||
|  |         deviceTypes.clear(); | ||||||
|  |         monthlyNumberOfCerts.clear(); | ||||||
|  |         monthlyNumberOfCertsPerOrgPerYear.clear(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -5,13 +5,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi::CertObjects { | ||||||
|  |  | ||||||
|     namespace CertObjects { |  | ||||||
|  |  | ||||||
|     struct CertificateEntry { |     struct CertificateEntry { | ||||||
|         OpenWifi::Types::UUID_t         id; |         OpenWifi::Types::UUID_t         id; | ||||||
| @@ -33,6 +30,7 @@ namespace OpenWifi { | |||||||
|         uint64_t                        modified = 0; |         uint64_t                        modified = 0; | ||||||
|         uint64_t                        revoked = 0; |         uint64_t                        revoked = 0; | ||||||
|         uint64_t                        revokeCount = 0; |         uint64_t                        revokeCount = 0; | ||||||
|  |         uint64_t                        synched = 0; | ||||||
|  |  | ||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -97,5 +95,28 @@ namespace OpenWifi { | |||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|     } |  | ||||||
|  |     struct DashBoardYearlyStats { | ||||||
|  |         uint64_t                            year=0; | ||||||
|  |         OpenWifi::Types::Counted3DMapSII    activeCerts; | ||||||
|  |         OpenWifi::Types::Counted3DMapSII    revokedCerts; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct Dashboard { | ||||||
|  |         uint64_t                            snapshot=0; | ||||||
|  |         uint64_t                            numberOfIssuedCerts=0; | ||||||
|  |         uint64_t                            numberOfRevokedCerts=0; | ||||||
|  |         OpenWifi::Types::CountedMap         activeCertsPerOrganization; | ||||||
|  |         OpenWifi::Types::CountedMap         revokedCertsPerOrganization; | ||||||
|  |         OpenWifi::Types::CountedMap         numberOfRedirectors; | ||||||
|  |         OpenWifi::Types::CountedMap         deviceTypes; | ||||||
|  |         OpenWifi::Types::CountedMap         monthlyNumberOfCerts; | ||||||
|  |         std::vector<DashBoardYearlyStats>   monthlyNumberOfCertsPerOrgPerYear; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         void reset(); | ||||||
|  |     }; | ||||||
|  |  | ||||||
| } | } | ||||||
							
								
								
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-08-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::EmbedDocument; | ||||||
|  |  | ||||||
|  | #include "RESTAPI_OWLSobjects.h" | ||||||
|  |  | ||||||
|  | // SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d | ||||||
|  |  | ||||||
|  | namespace OpenWifi::OWLSObjects { | ||||||
|  |  | ||||||
|  |     void SimulationDetails::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"name", name); | ||||||
|  |         field_to_json(Obj,"gateway", gateway); | ||||||
|  |         field_to_json(Obj,"certificate", certificate); | ||||||
|  |         field_to_json(Obj,"key", key); | ||||||
|  |         field_to_json(Obj,"macPrefix", macPrefix); | ||||||
|  |         field_to_json(Obj,"deviceType", deviceType); | ||||||
|  |         field_to_json(Obj,"devices", devices); | ||||||
|  |         field_to_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||||
|  |         field_to_json(Obj,"stateInterval", stateInterval); | ||||||
|  |         field_to_json(Obj,"minAssociations", minAssociations); | ||||||
|  |         field_to_json(Obj,"maxAssociations", maxAssociations); | ||||||
|  |         field_to_json(Obj,"minClients", minClients); | ||||||
|  |         field_to_json(Obj,"maxClients", maxClients); | ||||||
|  |         field_to_json(Obj,"simulationLength", simulationLength); | ||||||
|  |         field_to_json(Obj,"threads", threads); | ||||||
|  |         field_to_json(Obj,"clientInterval", clientInterval); | ||||||
|  |         field_to_json(Obj,"keepAlive", keepAlive); | ||||||
|  |         field_to_json(Obj,"reconnectInterval", reconnectInterval); | ||||||
|  |         field_to_json(Obj,"concurrentDevices", concurrentDevices); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"name", name); | ||||||
|  |             field_from_json(Obj,"gateway", gateway); | ||||||
|  |             field_from_json(Obj,"certificate", certificate); | ||||||
|  |             field_from_json(Obj,"key", key); | ||||||
|  |             field_from_json(Obj,"macPrefix", macPrefix); | ||||||
|  |             field_from_json(Obj,"deviceType", deviceType); | ||||||
|  |             field_from_json(Obj,"devices", devices); | ||||||
|  |             field_from_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||||
|  |             field_from_json(Obj,"stateInterval", stateInterval); | ||||||
|  |             field_from_json(Obj,"minAssociations", minAssociations); | ||||||
|  |             field_from_json(Obj,"maxAssociations", maxAssociations); | ||||||
|  |             field_from_json(Obj,"minClients", minClients); | ||||||
|  |             field_from_json(Obj,"maxClients", maxClients); | ||||||
|  |             field_from_json(Obj,"simulationLength", simulationLength); | ||||||
|  |             field_from_json(Obj,"threads", threads); | ||||||
|  |             field_from_json(Obj,"clientInterval", clientInterval); | ||||||
|  |             field_from_json(Obj,"keepAlive", keepAlive); | ||||||
|  |             field_from_json(Obj,"reconnectInterval", reconnectInterval); | ||||||
|  |             field_from_json(Obj,"concurrentDevices", concurrentDevices); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"list", list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"list", list); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SimulationStatus::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"simulationId", simulationId); | ||||||
|  |         field_to_json(Obj,"state", state); | ||||||
|  |         field_to_json(Obj,"tx", tx); | ||||||
|  |         field_to_json(Obj,"rx", rx); | ||||||
|  |         field_to_json(Obj,"msgsTx", msgsTx); | ||||||
|  |         field_to_json(Obj,"msgsRx", msgsRx); | ||||||
|  |         field_to_json(Obj,"liveDevices", liveDevices); | ||||||
|  |         field_to_json(Obj,"timeToFullDevices", timeToFullDevices); | ||||||
|  |         field_to_json(Obj,"startTime", startTime); | ||||||
|  |         field_to_json(Obj,"endTime", endTime); | ||||||
|  |         field_to_json(Obj,"errorDevices", errorDevices); | ||||||
|  |         field_to_json(Obj,"owner", owner); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::reset() { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-08-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
|  | #define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  | #include "Poco/JSON/Object.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi::OWLSObjects { | ||||||
|  |  | ||||||
|  |     struct SimulationDetails { | ||||||
|  |         std::string     id; | ||||||
|  |         std::string     name; | ||||||
|  |         std::string     gateway; | ||||||
|  |         std::string     certificate; | ||||||
|  |         std::string     key; | ||||||
|  |         std::string     macPrefix; | ||||||
|  |         std::string     deviceType; | ||||||
|  |         uint64_t        devices = 5; | ||||||
|  |         uint64_t        healthCheckInterval = 60; | ||||||
|  |         uint64_t        stateInterval = 60 ; | ||||||
|  |         uint64_t        minAssociations = 1; | ||||||
|  |         uint64_t        maxAssociations = 3; | ||||||
|  |         uint64_t        minClients = 1 ; | ||||||
|  |         uint64_t        maxClients = 3; | ||||||
|  |         uint64_t        simulationLength = 60 * 60; | ||||||
|  |         uint64_t        threads = 16; | ||||||
|  |         uint64_t        clientInterval = 1; | ||||||
|  |         uint64_t        keepAlive = 300; | ||||||
|  |         uint64_t        reconnectInterval = 30 ; | ||||||
|  |         uint64_t        concurrentDevices = 5; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SimulationDetailsList { | ||||||
|  |         std::vector<SimulationDetails>  list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SimulationStatus { | ||||||
|  |         std::string     id; | ||||||
|  |         std::string     simulationId; | ||||||
|  |         std::string     state; | ||||||
|  |         uint64_t        tx; | ||||||
|  |         uint64_t        rx; | ||||||
|  |         uint64_t        msgsTx; | ||||||
|  |         uint64_t        msgsRx; | ||||||
|  |         uint64_t        liveDevices; | ||||||
|  |         uint64_t        timeToFullDevices; | ||||||
|  |         uint64_t        startTime; | ||||||
|  |         uint64_t        endTime; | ||||||
|  |         uint64_t        errorDevices; | ||||||
|  |         std::string     owner; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     struct Dashboard { | ||||||
|  |         int O; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         void reset(); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
| @@ -9,6 +9,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <type_traits> | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "Poco/Data/LOB.h" | #include "Poco/Data/LOB.h" | ||||||
| @@ -27,8 +28,13 @@ namespace OpenWifi { | |||||||
|             bool Delete_ = true; |             bool Delete_ = true; | ||||||
|             bool PortalLogin_ = true; |             bool PortalLogin_ = true; | ||||||
|  |  | ||||||
|  |             AclTemplate()  noexcept = default; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         static_assert( std::is_nothrow_move_constructible_v<AclTemplate> ); | ||||||
|  |  | ||||||
|         struct WebToken { |         struct WebToken { | ||||||
|             std::string access_token_; |             std::string access_token_; | ||||||
| @@ -245,7 +251,8 @@ namespace OpenWifi { | |||||||
|             VERIFY_EMAIL, |             VERIFY_EMAIL, | ||||||
|             SUB_FORGOT_PASSWORD, |             SUB_FORGOT_PASSWORD, | ||||||
|             SUB_VERIFY_EMAIL, |             SUB_VERIFY_EMAIL, | ||||||
|             SUB_SIGNUP |             SUB_SIGNUP, | ||||||
|  |             EMAIL_INVITATION | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         struct ActionLink { |         struct ActionLink { | ||||||
|   | |||||||
| @@ -45,6 +45,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { |     bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|         CleanCache(); |         CleanCache(); | ||||||
|         uint64_t Now=OpenWifi::Now(); |         uint64_t Now=OpenWifi::Now(); | ||||||
|         auto Challenge = MFAServer::MakeChallenge(); |         auto Challenge = MFAServer::MakeChallenge(); | ||||||
| @@ -56,6 +58,9 @@ namespace OpenWifi { | |||||||
|     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { |     bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |  | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|         for(const auto &i:Cache_) { |         for(const auto &i:Cache_) { | ||||||
|             if(i.Number==Number && i.UserName==UserName) |             if(i.Number==Number && i.UserName==UserName) | ||||||
|                 return i.Validated; |                 return i.Validated; | ||||||
| @@ -66,6 +71,9 @@ namespace OpenWifi { | |||||||
|     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { |     bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) { | ||||||
|         std::lock_guard     G(Mutex_); |         std::lock_guard     G(Mutex_); | ||||||
|  |  | ||||||
|  |         if(!Enabled_) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|         for(auto &i:Cache_) { |         for(auto &i:Cache_) { | ||||||
|             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { |             if(i.Code==Code && i.Number==Number && i.UserName==UserName) { | ||||||
|                 i.Validated=true; |                 i.Validated=true; | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
| #include "Poco/Exception.h" | #include "Poco/Exception.h" | ||||||
| #include "Poco/Net/SSLManager.h" | #include "Poco/Net/SSLManager.h" | ||||||
| #include "Poco/Net/Context.h" | #include "Poco/Net/Context.h" | ||||||
|  | #include "Poco/Net/NetException.h" | ||||||
|  |  | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| @@ -31,7 +32,9 @@ namespace OpenWifi { | |||||||
|             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); |             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); | ||||||
|             MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60); |             MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||||
|             MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); |             MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||||
|  |             UseHTML_ = MicroService::instance().ConfigGetBool("mailer.html",false); | ||||||
|             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); |             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||||
|  |             EmailLogo_ = TemplateDir_ + "/" + MicroService::instance().ConfigGetString("mailer.logo","logo.jpg"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -58,14 +61,14 @@ namespace OpenWifi { | |||||||
|         PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(), |         PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(), | ||||||
|                                             .LastTry=0, |                                             .LastTry=0, | ||||||
|                                             .Sent=0, |                                             .Sent=0, | ||||||
|                                             .File=Poco::File(TemplateDir_ + "/" +Name), |                                             .TemplateName=Name, | ||||||
|                                             .Attrs=Attrs}); |                                             .Attrs=Attrs}); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void SMTPMailerService::run() { |     void SMTPMailerService::run() { | ||||||
|         Running_ = true; |         Running_ = true; | ||||||
|  |         Utils::SetThreadName("smtp-mailer"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|  |  | ||||||
|             Poco::Thread::trySleep(10000); |             Poco::Thread::trySleep(10000); | ||||||
| @@ -83,12 +86,20 @@ namespace OpenWifi { | |||||||
|                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; |                 auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second; | ||||||
|                 uint64_t now = OpenWifi::Now(); |                 uint64_t now = OpenWifi::Now(); | ||||||
|                 if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) { |                 if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) { | ||||||
|                     if (SendIt(*i)) { |                     switch(SendIt(*i)) { | ||||||
|  |                         case MessageSendStatus::msg_sent: { | ||||||
|                             Logger().information(fmt::format("Attempting to deliver for mail '{}'.", Recipient)); |                             Logger().information(fmt::format("Attempting to deliver for mail '{}'.", Recipient)); | ||||||
|                             i = Messages_.erase(i); |                             i = Messages_.erase(i); | ||||||
|                     } else { |                         } break; | ||||||
|  |                         case MessageSendStatus::msg_not_sent_but_resend: { | ||||||
|  |                             Logger().information(fmt::format("Mail for '{}' was not. We will retry later.", Recipient)); | ||||||
|                             i->LastTry = now; |                             i->LastTry = now; | ||||||
|                             ++i; |                             ++i; | ||||||
|  |                         } break; | ||||||
|  |                         case MessageSendStatus::msg_not_sent_but_do_not_resend: { | ||||||
|  |                             Logger().information(fmt::format("Mail for '{}' will not be sent. Check email address", Recipient)); | ||||||
|  |                             i = Messages_.erase(i); | ||||||
|  |                         } break; | ||||||
|                     } |                     } | ||||||
|                 } else if ((now-i->Posted)>MailAbandon_) { |                 } else if ((now-i->Posted)>MailAbandon_) { | ||||||
|                     Logger().information(fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient)); |                     Logger().information(fmt::format("Mail for '{}' has timed out and will not be sent.", Recipient)); | ||||||
| @@ -106,14 +117,12 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { |     MessageSendStatus SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||||
|  |  | ||||||
|         std::string             Recipient; |         std::string             Recipient; | ||||||
|  |  | ||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             Poco::Net::MailMessage  Message; |  | ||||||
|             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; |  | ||||||
|  |  | ||||||
|             auto H1 = Msg.Attrs.find(SENDER); |             auto H1 = Msg.Attrs.find(SENDER); | ||||||
|             std::string TheSender; |             std::string TheSender; | ||||||
|             if(H1!=Msg.Attrs.end()) { |             if(H1!=Msg.Attrs.end()) { | ||||||
| @@ -121,32 +130,38 @@ namespace OpenWifi { | |||||||
|             } else { |             } else { | ||||||
|                 TheSender = Sender_ ; |                 TheSender = Sender_ ; | ||||||
|             } |             } | ||||||
|             Message.setSender( TheSender ); |  | ||||||
|  |             auto Message = std::make_unique<Poco::Net::MailMessage>(); | ||||||
|  |  | ||||||
|  |             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||||
|  |             Message->setSender( TheSender ); | ||||||
|  |             Message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||||
|  |             Message->setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||||
|  |  | ||||||
|             Logger().information(fmt::format("Sending message to:{} from {}",Recipient,TheSender)); |             Logger().information(fmt::format("Sending message to:{} from {}",Recipient,TheSender)); | ||||||
|             Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); |  | ||||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); |  | ||||||
|  |  | ||||||
|             if(Msg.Attrs.find(TEXT) != Msg.Attrs.end()) { |             if(Msg.Attrs.find(TEXT) != Msg.Attrs.end()) { | ||||||
|                 std::string Content = Msg.Attrs.find(TEXT)->second; |                 std::string Content = Msg.Attrs.find(TEXT)->second; | ||||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); |                 Message->addContent(new Poco::Net::StringPartSource(Content)); | ||||||
|             } else { |             } else { | ||||||
|                 std::string Content = Utils::LoadFile(Msg.File); |                 for(const auto &format:{"html","txt"}) { | ||||||
|                 // std::cout << "Mailing " << Content << std::endl; |                     std::string Content = Utils::LoadFile(TemplateDir_ + Msg.TemplateName + "." + format ); | ||||||
|                     Types::StringPairVec Variables; |                     Types::StringPairVec Variables; | ||||||
|                     FillVariables(Msg.Attrs, Variables); |                     FillVariables(Msg.Attrs, Variables); | ||||||
|                     Utils::ReplaceVariables(Content, Variables); |                     Utils::ReplaceVariables(Content, Variables); | ||||||
|                 // std::cout << "Mailing " << Content << std::endl; |                     Message->addContent( | ||||||
|                 Message.addContent(new Poco::Net::StringPartSource(Content)); |                             new Poco::Net::StringPartSource(Content, (strcmp(format,"html") == 0 ? "text/html" : "text/plain") )); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             auto Logo = Msg.Attrs.find(LOGO); |             auto Logo = Msg.Attrs.find(LOGO); | ||||||
|             if(Logo!=Msg.Attrs.end()) { |             if(Logo!=Msg.Attrs.end()) { | ||||||
|                 try { |                 try { | ||||||
|                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); |                     Poco::File          LogoFile(EmailLogo_); | ||||||
|                     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); | ||||||
|                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); |                     Message->addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||||
|                 } catch (...) { |                 } catch (...) { | ||||||
|                     Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName())); |                     Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName())); | ||||||
|                 } |                 } | ||||||
| @@ -169,18 +184,23 @@ namespace OpenWifi { | |||||||
|                           SenderLoginUserName_, |                           SenderLoginUserName_, | ||||||
|                           SenderLoginPassword_ |                           SenderLoginPassword_ | ||||||
|             ); |             ); | ||||||
|             session.sendMessage(Message); |             session.sendMessage(*Message); | ||||||
|             session.close(); |             session.close(); | ||||||
|             return true; |             return MessageSendStatus::msg_sent; | ||||||
|  |         } | ||||||
|  |         catch (const Poco::Net::SMTPException &S) { | ||||||
|  |             Logger().log(S); | ||||||
|  |             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||||
|         } |         } | ||||||
|         catch (const Poco::Exception& E) |         catch (const Poco::Exception& E) | ||||||
|         { |         { | ||||||
|             Logger().log(E); |             Logger().log(E); | ||||||
|  |             return MessageSendStatus::msg_not_sent_but_resend; | ||||||
|         } |         } | ||||||
|         catch (const std::exception &E) { |         catch (const std::exception &E) { | ||||||
|             Logger().warning(fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what())); |             Logger().warning(fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what())); | ||||||
|  |             return MessageSendStatus::msg_not_sent_but_do_not_resend; | ||||||
|         } |         } | ||||||
|         return false; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,7 +27,8 @@ namespace OpenWifi { | |||||||
|         LOGO, |         LOGO, | ||||||
|         TEXT, |         TEXT, | ||||||
|         CHALLENGE_CODE, |         CHALLENGE_CODE, | ||||||
|         SENDER |         SENDER, | ||||||
|  |         ACTION_LINK_HTML | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     static const std::map<MESSAGE_ATTRIBUTES,const std::string> |     static const std::map<MESSAGE_ATTRIBUTES,const std::string> | ||||||
| @@ -44,7 +45,8 @@ namespace OpenWifi { | |||||||
|                                  {  LOGO, "LOGO"}, |                                  {  LOGO, "LOGO"}, | ||||||
|                                  {  TEXT, "TEXT"}, |                                  {  TEXT, "TEXT"}, | ||||||
|                                  {  CHALLENGE_CODE, "CHALLENGE_CODE"}, |                                  {  CHALLENGE_CODE, "CHALLENGE_CODE"}, | ||||||
|                                  {  SENDER, "SENDER"} |                                  {  SENDER, "SENDER"}, | ||||||
|  |                                  {  ACTION_LINK_HTML, "ACTION_LINK_HTML"}, | ||||||
|                                  }; |                                  }; | ||||||
|  |  | ||||||
|     inline const std::string & MessageAttributeToVar(MESSAGE_ATTRIBUTES Attr) { |     inline const std::string & MessageAttributeToVar(MESSAGE_ATTRIBUTES Attr) { | ||||||
| @@ -56,6 +58,12 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|     typedef std::map<MESSAGE_ATTRIBUTES, std::string>   MessageAttributes; |     typedef std::map<MESSAGE_ATTRIBUTES, std::string>   MessageAttributes; | ||||||
|  |  | ||||||
|  |     enum class MessageSendStatus { | ||||||
|  |         msg_sent, | ||||||
|  |         msg_not_sent_but_resend, | ||||||
|  |         msg_not_sent_but_do_not_resend | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     class SMTPMailerService : public SubSystemServer, Poco::Runnable { |     class SMTPMailerService : public SubSystemServer, Poco::Runnable { | ||||||
|         public: |         public: | ||||||
|            static SMTPMailerService *instance() { |            static SMTPMailerService *instance() { | ||||||
| @@ -67,7 +75,7 @@ namespace OpenWifi { | |||||||
|                uint64_t             Posted=0; |                uint64_t             Posted=0; | ||||||
|                uint64_t             LastTry=0; |                uint64_t             LastTry=0; | ||||||
|                uint64_t             Sent=0; |                uint64_t             Sent=0; | ||||||
|                Poco::File           File; |                std::string          TemplateName; | ||||||
|                MessageAttributes    Attrs; |                MessageAttributes    Attrs; | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
| @@ -76,7 +84,7 @@ namespace OpenWifi { | |||||||
|             void Stop() override; |             void Stop() override; | ||||||
|  |  | ||||||
|             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); |             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); | ||||||
|             bool SendIt(const MessageEvent &Msg); |             MessageSendStatus SendIt(const MessageEvent &Msg); | ||||||
|             void LoadMyConfig(); |             void LoadMyConfig(); | ||||||
|             void reinitialize(Poco::Util::Application &self) override; |             void reinitialize(Poco::Util::Application &self) override; | ||||||
|             bool Enabled() const { return Enabled_; } |             bool Enabled() const { return Enabled_; } | ||||||
| @@ -96,6 +104,8 @@ namespace OpenWifi { | |||||||
|             Poco::Thread            SenderThr_; |             Poco::Thread            SenderThr_; | ||||||
|             std::atomic_bool        Running_=false; |             std::atomic_bool        Running_=false; | ||||||
|             bool                    Enabled_=false; |             bool                    Enabled_=false; | ||||||
|  |             bool                    UseHTML_=false; | ||||||
|  |             std::string             EmailLogo_{"logo.jpg"}; | ||||||
|  |  | ||||||
|             SMTPMailerService() noexcept: |             SMTPMailerService() noexcept: | ||||||
|                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") |                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") | ||||||
|   | |||||||
| @@ -51,7 +51,7 @@ namespace OpenWifi { | |||||||
| 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | 		Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer); | ||||||
| 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | 		Timer_.setStartInterval( 5 * 60 * 1000);  // first run in 5 minutes | ||||||
| 		Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | 		Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | ||||||
| 		Timer_.start(*Archivercallback_); | 		Timer_.start(*Archivercallback_, MicroService::instance().TimerPool()); | ||||||
|  |  | ||||||
| 		return 0; | 		return 0; | ||||||
|     } |     } | ||||||
| @@ -63,6 +63,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) { |     void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||||
|  |         Utils::SetThreadName("strg-arch"); | ||||||
|         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); |         Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER"); | ||||||
|         logger.information("Squiggy the DB: removing old tokens."); |         logger.information("Squiggy the DB: removing old tokens."); | ||||||
|         StorageService()->SubTokenDB().CleanExpiredTokens(); |         StorageService()->SubTokenDB().CleanExpiredTokens(); | ||||||
|   | |||||||
| @@ -41,7 +41,6 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { |         std::string GenerateQRCode(const std::string &Secret, const std::string &email) { | ||||||
|  |  | ||||||
|             std::string uri{ |             std::string uri{ | ||||||
|                 "otpauth://totp/" + Issuer_ + ":" + |                 "otpauth://totp/" + Issuer_ + ":" + | ||||||
|                 email + "?secret=" + Secret + "&issuer=" + Issuer_ |                 email + "?secret=" + Secret + "&issuer=" + Issuer_ | ||||||
| @@ -55,10 +54,10 @@ namespace OpenWifi { | |||||||
|         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { |         static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) { | ||||||
|             uint64_t Now = OpenWifi::Now(); |             uint64_t Now = OpenWifi::Now(); | ||||||
|             uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6); |             uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6); | ||||||
|             char buffer[16]; |             char buffer[16]{0}; | ||||||
|             sprintf(buffer,"%06u",p); |             sprintf(buffer,"%06u",p); | ||||||
|             Expecting = buffer; |             Expecting = std::string(buffer); | ||||||
|             return Code == buffer; |             return Code == Expecting; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Start() override { |         int Start() override { | ||||||
| @@ -92,26 +91,13 @@ namespace OpenWifi { | |||||||
|             auto Secret = GenerateSecret(20, Base32Secret); |             auto Secret = GenerateSecret(20, Base32Secret); | ||||||
|             QRCode = GenerateQRCode(Base32Secret, User.email); |             QRCode = GenerateQRCode(Base32Secret, User.email); | ||||||
|  |  | ||||||
| /* |  | ||||||
|         struct Entry { |  | ||||||
|             bool        Subscriber=false; |  | ||||||
|             uint64_t    Start = 0; |  | ||||||
|             uint64_t    Done = 0 ; |  | ||||||
|             uint64_t    Verifications = 0 ; |  | ||||||
|             std::string Secret; |  | ||||||
|             std::string QRCode; |  | ||||||
|             std::string LastCode; |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
|             Entry E{ .Subscriber = Subscriber, |             Entry E{ .Subscriber = Subscriber, | ||||||
|                      .Start = OpenWifi::Now(), |                      .Start = OpenWifi::Now(), | ||||||
|                      .Done = 0, |                      .Done = 0, | ||||||
|                      .Verifications = 0, |                      .Verifications = 0, | ||||||
|                      .Secret = Secret, |                      .Secret = Secret, | ||||||
|                      .QRCode = QRCode, |                      .QRCode = QRCode, | ||||||
|                      .LastCode = 0 |                      .LastCode = "" | ||||||
|                      }; |                      }; | ||||||
|             Cache_[User.id] = E; |             Cache_[User.id] = E; | ||||||
|             return true; |             return true; | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ | |||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | static const std::string GitUCentralJSONSchemaFile{ | ||||||
|  | 	"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||||
|  |  | ||||||
| static json DefaultUCentralSchema = R"( | static json DefaultUCentralSchema = R"( | ||||||
|  |  | ||||||
| @@ -669,6 +670,47 @@ namespace OpenWifi { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"interface.ipv4.port-forward": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"enum": [ | ||||||
|  | 						"tcp", | ||||||
|  | 						"udp", | ||||||
|  | 						"any" | ||||||
|  | 					], | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"external-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				}, | ||||||
|  | 				"internal-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv4", | ||||||
|  | 					"example": "0.0.0.120" | ||||||
|  | 				}, | ||||||
|  | 				"internal-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"external-port", | ||||||
|  | 				"internal-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
| 		"interface.ipv4": { | 		"interface.ipv4": { | ||||||
| 			"type": "object", | 			"type": "object", | ||||||
| 			"properties": { | 			"properties": { | ||||||
| @@ -722,6 +764,12 @@ namespace OpenWifi { | |||||||
| 					"items": { | 					"items": { | ||||||
| 						"$ref": "#/$defs/interface.ipv4.dhcp-lease" | 						"$ref": "#/$defs/interface.ipv4.dhcp-lease" | ||||||
| 					} | 					} | ||||||
|  | 				}, | ||||||
|  | 				"port-forward": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv4.port-forward" | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -751,6 +799,96 @@ namespace OpenWifi { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"interface.ipv6.port-forward": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"enum": [ | ||||||
|  | 						"tcp", | ||||||
|  | 						"udp", | ||||||
|  | 						"any" | ||||||
|  | 					], | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"external-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				}, | ||||||
|  | 				"internal-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv6", | ||||||
|  | 					"example": "::1234:abcd" | ||||||
|  | 				}, | ||||||
|  | 				"internal-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"external-port", | ||||||
|  | 				"internal-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
|  | 		"interface.ipv6.traffic-allow": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"source-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "uc-cidr6", | ||||||
|  | 					"example": "2001:db8:1234:abcd::/64", | ||||||
|  | 					"default": "::/0" | ||||||
|  | 				}, | ||||||
|  | 				"source-ports": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"minItems": 1, | ||||||
|  | 					"items": { | ||||||
|  | 						"type": [ | ||||||
|  | 							"integer", | ||||||
|  | 							"string" | ||||||
|  | 						], | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 65535, | ||||||
|  | 						"format": "uc-portrange" | ||||||
|  | 					} | ||||||
|  | 				}, | ||||||
|  | 				"destination-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv6", | ||||||
|  | 					"example": "::1000" | ||||||
|  | 				}, | ||||||
|  | 				"destination-ports": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"minItems": 1, | ||||||
|  | 					"items": { | ||||||
|  | 						"type": [ | ||||||
|  | 							"integer", | ||||||
|  | 							"string" | ||||||
|  | 						], | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 65535, | ||||||
|  | 						"format": "uc-portrange" | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"destination-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
| 		"interface.ipv6": { | 		"interface.ipv6": { | ||||||
| 			"type": "object", | 			"type": "object", | ||||||
| 			"properties": { | 			"properties": { | ||||||
| @@ -782,6 +920,18 @@ namespace OpenWifi { | |||||||
| 				}, | 				}, | ||||||
| 				"dhcpv6": { | 				"dhcpv6": { | ||||||
| 					"$ref": "#/$defs/interface.ipv6.dhcpv6" | 					"$ref": "#/$defs/interface.ipv6.dhcpv6" | ||||||
|  | 				}, | ||||||
|  | 				"port-forward": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv6.port-forward" | ||||||
|  | 					} | ||||||
|  | 				}, | ||||||
|  | 				"traffic-allow": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv6.traffic-allow" | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -866,7 +1016,7 @@ namespace OpenWifi { | |||||||
| 				}, | 				}, | ||||||
| 				"gateway-fqdn": { | 				"gateway-fqdn": { | ||||||
| 					"type": "string", | 					"type": "string", | ||||||
| 					"format": "fqdn", | 					"format": "uc-fqdn", | ||||||
| 					"default": "ucentral.splash" | 					"default": "ucentral.splash" | ||||||
| 				}, | 				}, | ||||||
| 				"max-clients": { | 				"max-clients": { | ||||||
| @@ -901,6 +1051,7 @@ namespace OpenWifi { | |||||||
| 						"psk", | 						"psk", | ||||||
| 						"psk2", | 						"psk2", | ||||||
| 						"psk-mixed", | 						"psk-mixed", | ||||||
|  | 						"psk2-radius", | ||||||
| 						"wpa", | 						"wpa", | ||||||
| 						"wpa2", | 						"wpa2", | ||||||
| 						"wpa-mixed", | 						"wpa-mixed", | ||||||
| @@ -961,6 +1112,10 @@ namespace OpenWifi { | |||||||
| 					"type": "boolean", | 					"type": "boolean", | ||||||
| 					"default": false | 					"default": false | ||||||
| 				}, | 				}, | ||||||
|  | 				"reduced-neighbor-reporting": { | ||||||
|  | 					"type": "boolean", | ||||||
|  | 					"default": false | ||||||
|  | 				}, | ||||||
| 				"lci": { | 				"lci": { | ||||||
| 					"type": "string" | 					"type": "string" | ||||||
| 				}, | 				}, | ||||||
| @@ -1527,6 +1682,11 @@ namespace OpenWifi { | |||||||
| 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | ||||||
| 					"type": "string" | 					"type": "string" | ||||||
| 				}, | 				}, | ||||||
|  | 				"fils-discovery-interval": { | ||||||
|  | 					"type": "integer", | ||||||
|  | 					"default": 20, | ||||||
|  | 					"maximum": 10000 | ||||||
|  | 				}, | ||||||
| 				"encryption": { | 				"encryption": { | ||||||
| 					"$ref": "#/$defs/interface.ssid.encryption" | 					"$ref": "#/$defs/interface.ssid.encryption" | ||||||
| 				}, | 				}, | ||||||
| @@ -2087,6 +2247,10 @@ namespace OpenWifi { | |||||||
| 				"auto-channel": { | 				"auto-channel": { | ||||||
| 					"type": "boolean", | 					"type": "boolean", | ||||||
| 					"default": false | 					"default": false | ||||||
|  | 				}, | ||||||
|  | 				"ipv6": { | ||||||
|  | 					"type": "boolean", | ||||||
|  | 					"default": false | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -2193,7 +2357,7 @@ namespace OpenWifi { | |||||||
| 									"properties": { | 									"properties": { | ||||||
| 										"fqdn": { | 										"fqdn": { | ||||||
| 											"type": "string", | 											"type": "string", | ||||||
| 											"format": "fqdn" | 											"format": "uc-fqdn" | ||||||
| 										}, | 										}, | ||||||
| 										"suffix-matching": { | 										"suffix-matching": { | ||||||
| 											"type": "boolean", | 											"type": "boolean", | ||||||
| @@ -2444,7 +2608,6 @@ namespace OpenWifi { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| )"_json; | )"_json; | ||||||
|  |  | ||||||
|     class custom_error_handler : public nlohmann::json_schema::basic_error_handler |     class custom_error_handler : public nlohmann::json_schema::basic_error_handler | ||||||
| @@ -2460,9 +2623,18 @@ namespace OpenWifi { | |||||||
|     void ConfigurationValidator::Init() { |     void ConfigurationValidator::Init() { | ||||||
|         if(Initialized_) |         if(Initialized_) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|         std::string GitSchema; |         std::string GitSchema; | ||||||
|  | 		if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) { | ||||||
|  | 			RootSchema_ = DefaultUCentralSchema; | ||||||
|  | 			Logger().information("Using uCentral validation from built-in default."); | ||||||
|  | 			Initialized_ = Working_ = true; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { | 			auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile); | ||||||
|  |             if(Utils::wgets(GitURI, GitSchema)) { | ||||||
|                 RootSchema_ = json::parse(GitSchema); |                 RootSchema_ = json::parse(GitSchema); | ||||||
|                 Logger().information("Using uCentral validation schema from GIT."); |                 Logger().information("Using uCentral validation schema from GIT."); | ||||||
|             } else { |             } else { | ||||||
| @@ -2528,6 +2700,17 @@ namespace OpenWifi { | |||||||
|         return IsCIDRv4(value) || IsCIDRv6(value); |         return IsCIDRv4(value) || IsCIDRv6(value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     static inline bool IsPortRangeIsValid(const std::string &r) { | ||||||
|  |         const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM); | ||||||
|  |  | ||||||
|  |         for(const auto &port:ports) { | ||||||
|  |             uint32_t port_num = std::stoul(port); | ||||||
|  |             if(port_num==0 || port_num>65535) | ||||||
|  |                 return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) |     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) | ||||||
|     { |     { | ||||||
|         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; |         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; | ||||||
| @@ -2578,6 +2761,14 @@ namespace OpenWifi { | |||||||
|             } catch (...) { |             } catch (...) { | ||||||
|             } |             } | ||||||
|             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); |             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); | ||||||
|  |         } else if(format == "uc-portrange") { | ||||||
|  |             try { | ||||||
|  |                 if(IsPortRangeIsValid(value)) | ||||||
|  |                     return; | ||||||
|  |                 throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||||
|  |             } catch (...) { | ||||||
|  |             } | ||||||
|  |             throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||||
|         } else if(format == "ip") { |         } else if(format == "ip") { | ||||||
|             if (IsIP(value)) |             if (IsIP(value)) | ||||||
|                 return; |                 return; | ||||||
|   | |||||||
| @@ -27,6 +27,11 @@ namespace OpenWifi { | |||||||
|     inline uint64_t Now() { return std::time(nullptr); }; |     inline uint64_t Now() { return std::time(nullptr); }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | namespace OpenWifi::Utils { | ||||||
|  |     std::vector<unsigned char> base64decode(const std::string& input); | ||||||
|  |     std::string base64encode(const unsigned char *input, uint32_t size); | ||||||
|  | } | ||||||
|  |  | ||||||
| using namespace std::chrono_literals; | using namespace std::chrono_literals; | ||||||
|  |  | ||||||
| #include "Poco/Util/Application.h" | #include "Poco/Util/Application.h" | ||||||
| @@ -238,6 +243,11 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|         Obj.set(Field,Value); |         Obj.set(Field,Value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) { | ||||||
|  |         auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size()); | ||||||
|  |         Obj.set(Field,Result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { |     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { | ||||||
|         Poco::JSON::Array   Array; |         Poco::JSON::Array   Array; | ||||||
|         for(const auto &i:S) { |         for(const auto &i:S) { | ||||||
| @@ -377,6 +387,13 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|             Value = (uint64_t)Obj->get(Field); |             Value = (uint64_t)Obj->get(Field); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) { | ||||||
|  |         if(Obj->has(Field) && !Obj->isNull(Field)) { | ||||||
|  |             auto Result = Utils::base64decode(Obj->get(Field).toString()); | ||||||
|  |             Value.assignRaw((const unsigned char *)&Result[0],Result.size()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) { | ||||||
|         if(Obj->isArray(Field) && !Obj->isNull(Field)) { |         if(Obj->isArray(Field) && !Obj->isNull(Field)) { | ||||||
|             auto O = Obj->getArray(Field); |             auto O = Obj->getArray(Field); | ||||||
| @@ -643,6 +660,27 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|  |  | ||||||
| namespace OpenWifi::Utils { | namespace OpenWifi::Utils { | ||||||
|  |  | ||||||
|  | 	inline void SetThreadName(const char *name) { | ||||||
|  | #ifdef __linux__ | ||||||
|  | 		Poco::Thread::current()->setName(name); | ||||||
|  | 		pthread_setname_np(pthread_self(), name); | ||||||
|  | #endif | ||||||
|  | #ifdef __APPLE__ | ||||||
|  | 	Poco::Thread::current()->setName(name); | ||||||
|  | 	pthread_setname_np(name); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	inline void SetThreadName(Poco::Thread &thr, const char *name) { | ||||||
|  | #ifdef __linux__ | ||||||
|  | 		thr.setName(name); | ||||||
|  | 		pthread_setname_np(thr.tid(), name); | ||||||
|  | #endif | ||||||
|  | #ifdef __APPLE__ | ||||||
|  | 		thr.setName(name); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|     enum MediaTypeEncodings { |     enum MediaTypeEncodings { | ||||||
|         PLAIN, |         PLAIN, | ||||||
|         BINARY, |         BINARY, | ||||||
| @@ -665,6 +703,19 @@ namespace OpenWifi::Utils { | |||||||
|         return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0); |         return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | 	template <typename ...Args> std::string ComputeHash(Args&&... args) { | ||||||
|  | 		Poco::SHA2Engine    E; | ||||||
|  | 		auto as_string = [](auto p) { | ||||||
|  | 			if constexpr(std::is_arithmetic_v<decltype(p)>) { | ||||||
|  | 				return std::to_string(p); | ||||||
|  | 			} else { | ||||||
|  | 				return p; | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 		(E.update(as_string(args)),...); | ||||||
|  | 		return Poco::SHA2Engine::digestToHex(E.digest()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|     [[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) { |     [[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) { | ||||||
|         std::vector<std::string> ReturnList; |         std::vector<std::string> ReturnList; | ||||||
|  |  | ||||||
| @@ -1167,6 +1218,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"}; | ||||||
|     static const std::string uSERVICE_ANALYTICS{ "owanalytics"}; |     static const std::string uSERVICE_ANALYTICS{ "owanalytics"}; | ||||||
|  | 	static const std::string uSERVICE_OWRRM{ "owrrm"}; | ||||||
|  |  | ||||||
| 	class ConfigurationEntry { | 	class ConfigurationEntry { | ||||||
| 	  public: | 	  public: | ||||||
| @@ -1315,7 +1367,7 @@ namespace OpenWifi { | |||||||
| 		inline void Start(); | 		inline void Start(); | ||||||
| 		inline void Stop(); | 		inline void Stop(); | ||||||
| 	  private: | 	  private: | ||||||
| 		std::atomic_bool 	Running_ = false; | 		mutable std::atomic_bool 	Running_ = false; | ||||||
| 		Poco::Thread		Thread_; | 		Poco::Thread		Thread_; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -1360,13 +1412,14 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	    [[nodiscard]] inline const std::string &Address() const { return address_; }; | 	    [[nodiscard]] inline const std::string &Address() const { return address_; }; | ||||||
| 	    [[nodiscard]] inline uint32_t Port() const { return port_; }; | 	    [[nodiscard]] inline uint32_t Port() const { return port_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &KeyFile() const { return key_file_; }; | 	    [[nodiscard]] inline auto KeyFile() const { return key_file_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &CertFile() const { return cert_file_; }; | 	    [[nodiscard]] inline auto CertFile() const { return cert_file_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &RootCA() const { return root_ca_; }; | 	    [[nodiscard]] inline auto RootCA() const { return root_ca_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; }; | 	    [[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; }; | 	    [[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; }; | ||||||
| 	    [[nodiscard]] inline const std::string &Name() const { return name_; }; | 	    [[nodiscard]] inline auto Name() const { return name_; }; | ||||||
| 	    [[nodiscard]] inline int Backlog() const { return backlog_; } | 	    [[nodiscard]] inline int Backlog() const { return backlog_; } | ||||||
|  | 		[[nodiscard]] inline auto Cas() const { return cas_; } | ||||||
|  |  | ||||||
| 	    [[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const { | 	    [[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const { | ||||||
| 	        Poco::Net::Context::Params P; | 	        Poco::Net::Context::Params P; | ||||||
| @@ -1846,7 +1899,8 @@ namespace OpenWifi { | |||||||
| 	            Request = &RequestIn; | 	            Request = &RequestIn; | ||||||
| 	            Response = &ResponseIn; | 	            Response = &ResponseIn; | ||||||
|  |  | ||||||
| 				Poco::Thread::current()->setName("WebServerThread_" + std::to_string(TransactionId_)); | //				std::string th_name = "restsvr_" + std::to_string(TransactionId_); | ||||||
|  | //				Utils::SetThreadName(th_name.c_str()); | ||||||
|  |  | ||||||
|                 if(Request->getContentLength()>0) { |                 if(Request->getContentLength()>0) { | ||||||
|                     if(Request->getContentType().find("application/json")!=std::string::npos) { |                     if(Request->getContentType().find("application/json")!=std::string::npos) { | ||||||
| @@ -1895,28 +1949,24 @@ namespace OpenWifi { | |||||||
| 	    [[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; } | 	    [[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; } | ||||||
| 	    [[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; } | 	    [[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; } | ||||||
|  |  | ||||||
| /*	    [[nodiscard]] inline const Poco::JSON::Object::Ptr ParseStream() { |  | ||||||
| 	        return IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>(); |  | ||||||
| 	    } |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| 		inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) { | 		inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) { | ||||||
| 			bindings.clear(); | 			bindings.clear(); | ||||||
| 	        std::vector<std::string> PathItems = Utils::Split(Request, '/'); | 			auto PathItems = Poco::StringTokenizer(Request, "/"); | ||||||
|  |  | ||||||
| 			for(const auto &EndPoint:EndPoints) { | 			for(const auto &EndPoint:EndPoints) { | ||||||
| 	            std::vector<std::string> ParamItems = Utils::Split(EndPoint, '/'); | 				auto ParamItems = Poco::StringTokenizer(EndPoint, "/"); | ||||||
| 	            if (PathItems.size() != ParamItems.size()) | 				if (PathItems.count() != ParamItems.count()) | ||||||
| 					continue; | 					continue; | ||||||
|  |  | ||||||
| 				bool Matched = true; | 				bool Matched = true; | ||||||
| 	            for (size_t i = 0; i != PathItems.size() && Matched; i++) { | 				for (size_t i = 0; i < PathItems.count(); i++) { | ||||||
| 					if (PathItems[i] != ParamItems[i]) { | 					if (PathItems[i] != ParamItems[i]) { | ||||||
| 						if (ParamItems[i][0] == '{') { | 						if (ParamItems[i][0] == '{') { | ||||||
| 							auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2); | 							auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2); | ||||||
| 							bindings[Poco::toLower(ParamName)] = PathItems[i]; | 							bindings[Poco::toLower(ParamName)] = PathItems[i]; | ||||||
| 						} else { | 						} else { | ||||||
| 							Matched = false; | 							Matched = false; | ||||||
|  | 							break; | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -2045,6 +2095,17 @@ namespace OpenWifi { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) { | ||||||
|  |             if(O->has(Field)) { | ||||||
|  |                 std::string Content = O->get(Field).toString(); | ||||||
|  |                 auto DecodedBlob = Utils::base64decode(Content); | ||||||
|  |                 Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size()); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) { |         template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) { | ||||||
|             if(O->has(Field)) { |             if(O->has(Field)) { | ||||||
|                 assignee = value; |                 assignee = value; | ||||||
| @@ -2385,6 +2446,7 @@ namespace OpenWifi { | |||||||
|             Poco::Net::HTTPServerResponse       *Response= nullptr; |             Poco::Net::HTTPServerResponse       *Response= nullptr; | ||||||
|             SecurityObjects::UserInfoAndPolicy 	UserInfo_; |             SecurityObjects::UserInfoAndPolicy 	UserInfo_; | ||||||
|             QueryBlock					QB_; |             QueryBlock					QB_; | ||||||
|  | 			const std::string & Requester() const { return REST_Requester_; } | ||||||
| 	    protected: | 	    protected: | ||||||
| 	        BindingMap 					Bindings_; | 	        BindingMap 					Bindings_; | ||||||
| 	        Poco::URI::QueryParameters 	Parameters_; | 	        Poco::URI::QueryParameters 	Parameters_; | ||||||
| @@ -2401,6 +2463,7 @@ namespace OpenWifi { | |||||||
| 	        RateLimit                   MyRates_; | 	        RateLimit                   MyRates_; | ||||||
|             uint64_t                    TransactionId_; |             uint64_t                    TransactionId_; | ||||||
|             Poco::JSON::Object::Ptr     ParsedBody_; |             Poco::JSON::Object::Ptr     ParsedBody_; | ||||||
|  | 			std::string					REST_Requester_; | ||||||
| 	    }; | 	    }; | ||||||
|  |  | ||||||
| 	    class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { | 	    class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { | ||||||
| @@ -2582,7 +2645,7 @@ namespace OpenWifi { | |||||||
|     private: |     private: | ||||||
|         std::recursive_mutex  	Mutex_; |         std::recursive_mutex  	Mutex_; | ||||||
|         Poco::Thread        	Worker_; |         Poco::Thread        	Worker_; | ||||||
|         std::atomic_bool    	Running_=false; |         mutable std::atomic_bool    	Running_=false; | ||||||
| 		Poco::NotificationQueue	Queue_; | 		Poco::NotificationQueue	Queue_; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| @@ -2608,7 +2671,7 @@ namespace OpenWifi { | |||||||
| 	  private: | 	  private: | ||||||
| 		std::recursive_mutex  	Mutex_; | 		std::recursive_mutex  	Mutex_; | ||||||
|         Poco::Thread        	Worker_; |         Poco::Thread        	Worker_; | ||||||
|         std::atomic_bool    	Running_=false; |         mutable std::atomic_bool    	Running_=false; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| 	class KafkaDispatcher : public Poco::Runnable { | 	class KafkaDispatcher : public Poco::Runnable { | ||||||
| @@ -2665,6 +2728,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 		inline void run() override { | 		inline void run() override { | ||||||
| 			Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | 			Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | ||||||
|  | 			Utils::SetThreadName("kafka:dispatch"); | ||||||
| 			while(Note && Running_) { | 			while(Note && Running_) { | ||||||
| 				auto Msg = dynamic_cast<KafkaMessage*>(Note.get()); | 				auto Msg = dynamic_cast<KafkaMessage*>(Note.get()); | ||||||
| 				if(Msg!= nullptr) { | 				if(Msg!= nullptr) { | ||||||
| @@ -2690,7 +2754,7 @@ namespace OpenWifi { | |||||||
| 		std::recursive_mutex  		Mutex_; | 		std::recursive_mutex  		Mutex_; | ||||||
| 		Types::NotifyTable      	Notifiers_; | 		Types::NotifyTable      	Notifiers_; | ||||||
| 		Poco::Thread        		Worker_; | 		Poco::Thread        		Worker_; | ||||||
| 		std::atomic_bool    	Running_=false; | 		mutable std::atomic_bool    Running_=false; | ||||||
| 		uint64_t          			FunctionId_=1; | 		uint64_t          			FunctionId_=1; | ||||||
| 		Poco::NotificationQueue		Queue_; | 		Poco::NotificationQueue		Queue_; | ||||||
| 	}; | 	}; | ||||||
| @@ -2885,6 +2949,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	            void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override | 	            void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override | ||||||
| 	            { | 	            { | ||||||
|  | 					Utils::SetThreadName("alb-request"); | ||||||
| 					try { | 					try { | ||||||
| 						if((id_ % 100) == 0) { | 						if((id_ % 100) == 0) { | ||||||
| 							Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", | 							Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", | ||||||
| @@ -2953,7 +3018,7 @@ namespace OpenWifi { | |||||||
| 	    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; | ||||||
| 	    std::atomic_bool                            Running_=false; | 	    mutable std::atomic_bool                            Running_=false; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } | 	inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } | ||||||
| @@ -2973,7 +3038,7 @@ namespace OpenWifi { | |||||||
| 	    } | 	    } | ||||||
| 	    int Start() override; | 	    int Start() override; | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
| 	        Logger().information("Stopping "); | 	        Logger().information("Stopping..."); | ||||||
| 	        for( const auto & svr : RESTServers_ ) | 	        for( const auto & svr : RESTServers_ ) | ||||||
| 	            svr->stop(); | 	            svr->stop(); | ||||||
| 			Pool_.stopAll(); | 			Pool_.stopAll(); | ||||||
| @@ -2981,22 +3046,23 @@ namespace OpenWifi { | |||||||
| 	        RESTServers_.clear(); | 	        RESTServers_.clear(); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	    inline void reinitialize(Poco::Util::Application &self) override; | 	    inline void reinitialize(Poco::Util::Application &self) override; | ||||||
|  |  | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | ||||||
| 	        RESTAPIHandler::BindingMap Bindings; | 	        RESTAPIHandler::BindingMap Bindings; | ||||||
| 			Poco::Thread::current()->setName(fmt::format("RESTAPI_ExtServer_{}",Id)); | 			Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str()); | ||||||
| 	        return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id); | 	        return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id); | ||||||
| 	    } | 	    } | ||||||
|  |         const Poco::ThreadPool & Pool() { return Pool_; } | ||||||
|  |  | ||||||
| 	private: | 	private: | ||||||
| 	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_; | 	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_; | ||||||
| 	    Poco::ThreadPool	    Pool_; | 	    Poco::ThreadPool	    Pool_{"x-rest",2,32}; | ||||||
| 	    RESTAPI_GenericServer   Server_; | 	    RESTAPI_GenericServer   Server_; | ||||||
|  |  | ||||||
|         RESTAPI_ExtServer() noexcept: |         RESTAPI_ExtServer() noexcept: | ||||||
| 	    SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"), | 	    SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi") | ||||||
|         Pool_("RESTAPI_ExtServer",4,50,120) |  | ||||||
|             { |             { | ||||||
|             } |             } | ||||||
| 	}; | 	}; | ||||||
| @@ -3009,7 +3075,7 @@ namespace OpenWifi { | |||||||
| 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | ||||||
| 			try { | 			try { | ||||||
| 				Poco::URI uri(Request.getURI()); | 				Poco::URI uri(Request.getURI()); | ||||||
| 				Poco::Thread::current()->setName(fmt::format("ExtWebServer_{}",TransactionId_)); | 				Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str()); | ||||||
| 				return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++); | 				return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++); | ||||||
| 			} catch (...) { | 			} catch (...) { | ||||||
|  |  | ||||||
| @@ -3107,7 +3173,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	    inline int Start() override; | 	    inline int Start() override; | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
| 	        Logger().information("Stopping "); | 	        Logger().information("Stopping..."); | ||||||
| 	        for( const auto & svr : RESTServers_ ) | 	        for( const auto & svr : RESTServers_ ) | ||||||
| 	            svr->stop(); | 	            svr->stop(); | ||||||
| 			Pool_.stopAll(); | 			Pool_.stopAll(); | ||||||
| @@ -3118,17 +3184,18 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | ||||||
| 	        RESTAPIHandler::BindingMap Bindings; | 	        RESTAPIHandler::BindingMap Bindings; | ||||||
| 			Poco::Thread::current()->setName(fmt::format("RESTAPI_IntServer_{}",Id)); | 			Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str()); | ||||||
| 	        return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id); | 	        return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
|  |         const Poco::ThreadPool & Pool() { return Pool_; } | ||||||
| 	private: | 	private: | ||||||
| 	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_; | 	    std::vector<std::unique_ptr<Poco::Net::HTTPServer>>   RESTServers_; | ||||||
| 	    Poco::ThreadPool	    Pool_; | 	    Poco::ThreadPool	    Pool_{"i-rest",2,16}; | ||||||
| 	    RESTAPI_GenericServer   Server_; | 	    RESTAPI_GenericServer   Server_; | ||||||
|  |  | ||||||
|         RESTAPI_IntServer() noexcept: |         RESTAPI_IntServer() noexcept: | ||||||
| 		   SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi"), | 		   SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi") | ||||||
|             Pool_("RESTAPI_IntServer",4,50,120) |  | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
| 	}; | 	}; | ||||||
| @@ -3139,6 +3206,7 @@ namespace OpenWifi { | |||||||
| 	public: | 	public: | ||||||
|         inline IntRequestHandlerFactory() = default; |         inline IntRequestHandlerFactory() = default; | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | ||||||
|  | 			Utils::SetThreadName(fmt::format("i-rest:{}",TransactionId_).c_str()); | ||||||
| 	        Poco::URI uri(Request.getURI()); | 	        Poco::URI uri(Request.getURI()); | ||||||
| 	        return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_); | 	        return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_); | ||||||
| 	    } | 	    } | ||||||
| @@ -3182,7 +3250,6 @@ namespace OpenWifi { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		[[nodiscard]] std::string Version() { return Version_; } | 		[[nodiscard]] std::string Version() { return Version_; } | ||||||
| 		// [[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; } |  | ||||||
| 		[[nodiscard]] inline const std::string & DataDir() { return DataDir_; } | 		[[nodiscard]] inline const std::string & DataDir() { return DataDir_; } | ||||||
| 		[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; } | 		[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; } | ||||||
| 		[[nodiscard]] bool Debug() const { return DebugMode_; } | 		[[nodiscard]] bool Debug() const { return DebugMode_; } | ||||||
| @@ -3215,6 +3282,11 @@ namespace OpenWifi { | |||||||
|             return Poco::Logger::get(Name); |             return Poco::Logger::get(Name); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) { | ||||||
|  |             Cfg.set("additionalConfiguration",false); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         static inline void Exit(int Reason); |         static inline void Exit(int Reason); | ||||||
| 		inline void BusMessageReceived(const std::string &Key, const std::string & Payload); | 		inline void BusMessageReceived(const std::string &Key, const std::string & Payload); | ||||||
| 		inline MicroServiceMetaVec GetServices(const std::string & Type); | 		inline MicroServiceMetaVec GetServices(const std::string & Type); | ||||||
| @@ -3251,7 +3323,6 @@ namespace OpenWifi { | |||||||
| 		inline std::string ConfigPath(const std::string &Key); | 		inline std::string ConfigPath(const std::string &Key); | ||||||
| 		inline std::string Encrypt(const std::string &S); | 		inline std::string Encrypt(const std::string &S); | ||||||
| 		inline std::string Decrypt(const std::string &S); | 		inline std::string Decrypt(const std::string &S); | ||||||
| 		inline std::string CreateHash(const std::string &S); |  | ||||||
| 		inline std::string MakeSystemEventMessage( const std::string & Type ) const; | 		inline std::string MakeSystemEventMessage( const std::string & Type ) const; | ||||||
| 		[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); | 		[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); | ||||||
| 		inline static void SavePID(); | 		inline static void SavePID(); | ||||||
| @@ -3281,6 +3352,9 @@ namespace OpenWifi { | |||||||
|                 return Signer_.sign(T,Algo); |                 return Signer_.sign(T,Algo); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | 		inline Poco::ThreadPool & TimerPool() { return TimerPool_; } | ||||||
|  |  | ||||||
| 	  private: | 	  private: | ||||||
| 	    static MicroService         * instance_; | 	    static MicroService         * instance_; | ||||||
| 		bool                        HelpRequested_ = false; | 		bool                        HelpRequested_ = false; | ||||||
| @@ -3294,7 +3368,6 @@ namespace OpenWifi { | |||||||
| 		std::string                 WWWAssetsDir_; | 		std::string                 WWWAssetsDir_; | ||||||
| 		Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); | 		Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); | ||||||
| 		Poco::Crypto::Cipher        * Cipher_ = nullptr; | 		Poco::Crypto::Cipher        * Cipher_ = nullptr; | ||||||
| 		Poco::SHA2Engine			SHA2_; |  | ||||||
| 		MicroServiceMetaMap			Services_; | 		MicroServiceMetaMap			Services_; | ||||||
| 		std::string 				MyHash_; | 		std::string 				MyHash_; | ||||||
| 		std::string 				MyPrivateEndPoint_; | 		std::string 				MyPrivateEndPoint_; | ||||||
| @@ -3315,6 +3388,7 @@ namespace OpenWifi { | |||||||
|         bool                        NoBuiltInCrypto_=false; |         bool                        NoBuiltInCrypto_=false; | ||||||
|         Poco::JWT::Signer	        Signer_; |         Poco::JWT::Signer	        Signer_; | ||||||
| 		Poco::Logger				&Logger_; | 		Poco::Logger				&Logger_; | ||||||
|  | 		Poco::ThreadPool			TimerPool_{"timer:pool",2,16}; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| 	inline void MicroService::Exit(int Reason) { | 	inline void MicroService::Exit(int Reason) { | ||||||
| @@ -3464,7 +3538,7 @@ namespace OpenWifi { | |||||||
| 	    MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private"); | 	    MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private"); | ||||||
| 	    MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public"); | 	    MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public"); | ||||||
| 	    UIURI_ = ConfigGetString("openwifi.system.uri.ui"); | 	    UIURI_ = ConfigGetString("openwifi.system.uri.ui"); | ||||||
| 	    MyHash_ = CreateHash(MyPublicEndPoint_); | 	    MyHash_ = Utils::ComputeHash(MyPublicEndPoint_); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void MicroServicePostInitialization(); | 	void MicroServicePostInitialization(); | ||||||
| @@ -3801,11 +3875,6 @@ namespace OpenWifi { | |||||||
| 	    return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);; | 	    return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline std::string MicroService::CreateHash(const std::string &S) { |  | ||||||
| 	    SHA2_.update(S); |  | ||||||
| 	    return Utils::ToHex(SHA2_.digest()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const { | 	inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const { | ||||||
| 	    Poco::JSON::Object	Obj; | 	    Poco::JSON::Object	Obj; | ||||||
| 	    Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type); | 	    Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type); | ||||||
| @@ -3868,6 +3937,7 @@ namespace OpenWifi { | |||||||
|             Params->setMaxThreads(50); |             Params->setMaxThreads(50); | ||||||
|             Params->setMaxQueued(200); |             Params->setMaxQueued(200); | ||||||
|             Params->setKeepAlive(true); |             Params->setKeepAlive(true); | ||||||
|  | 			Params->setName("ws:xrest"); | ||||||
|  |  | ||||||
|             std::unique_ptr<Poco::Net::HTTPServer>  NewServer; |             std::unique_ptr<Poco::Net::HTTPServer>  NewServer; | ||||||
|             if(MicroService::instance().NoAPISecurity()) { |             if(MicroService::instance().NoAPISecurity()) { | ||||||
| @@ -3904,6 +3974,7 @@ namespace OpenWifi { | |||||||
|             Params->setMaxThreads(50); |             Params->setMaxThreads(50); | ||||||
|             Params->setMaxQueued(200); |             Params->setMaxQueued(200); | ||||||
|             Params->setKeepAlive(true); |             Params->setKeepAlive(true); | ||||||
|  | 			Params->setName("ws:irest"); | ||||||
|  |  | ||||||
|             std::unique_ptr<Poco::Net::HTTPServer>  NewServer; |             std::unique_ptr<Poco::Net::HTTPServer>  NewServer; | ||||||
|             if(MicroService::instance().NoAPISecurity()) { |             if(MicroService::instance().NoAPISecurity()) { | ||||||
| @@ -3921,7 +3992,6 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline int MicroService::main([[maybe_unused]] const ArgVec &args) { |     inline int MicroService::main([[maybe_unused]] const ArgVec &args) { | ||||||
|  |  | ||||||
| 	    MyErrorHandler	ErrorHandler(*this); | 	    MyErrorHandler	ErrorHandler(*this); | ||||||
| 	    Poco::ErrorHandler::set(&ErrorHandler); | 	    Poco::ErrorHandler::set(&ErrorHandler); | ||||||
|  |  | ||||||
| @@ -4028,6 +4098,7 @@ namespace OpenWifi { | |||||||
| 	        Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); | 	        Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); | ||||||
| 	        Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); | 	        Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); | ||||||
| 	        auto Params = new Poco::Net::HTTPServerParams; | 	        auto Params = new Poco::Net::HTTPServerParams; | ||||||
|  | 			Params->setName("ws:alb"); | ||||||
| 	        Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params); | 	        Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params); | ||||||
| 	        Server_->start(); | 	        Server_->start(); | ||||||
| 	    } | 	    } | ||||||
| @@ -4037,6 +4108,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     inline void BusEventManager::run() { |     inline void BusEventManager::run() { | ||||||
|         Running_ = true; |         Running_ = true; | ||||||
|  | 		Utils::SetThreadName("fmwk:EventMgr"); | ||||||
|         auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN); |         auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN); | ||||||
|         KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false); |         KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
| @@ -4122,6 +4194,8 @@ namespace OpenWifi { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void KafkaProducer::run() { | 	inline void KafkaProducer::run() { | ||||||
|  |  | ||||||
|  | 		Utils::SetThreadName("Kafka:Prod"); | ||||||
| 	    cppkafka::Configuration Config({ | 	    cppkafka::Configuration Config({ | ||||||
|             { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, |             { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||||
|             { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } |             { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } | ||||||
| @@ -4160,6 +4234,8 @@ namespace OpenWifi { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void KafkaConsumer::run() { | 	inline void KafkaConsumer::run() { | ||||||
|  | 		Utils::SetThreadName("Kafka:Cons"); | ||||||
|  |  | ||||||
| 	    cppkafka::Configuration Config({ | 	    cppkafka::Configuration Config({ | ||||||
| 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||||
| 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, | 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, | ||||||
| @@ -4298,6 +4374,11 @@ namespace OpenWifi { | |||||||
| 	            Answer.set("certificates", Certificates); | 	            Answer.set("certificates", Certificates); | ||||||
| 	            return ReturnObject(Answer); | 	            return ReturnObject(Answer); | ||||||
| 	        } | 	        } | ||||||
|  |             if(GetBoolParameter("extraConfiguration")) { | ||||||
|  |                 Poco::JSON::Object  Answer; | ||||||
|  |                 MicroService::instance().GetExtraConfiguration(Answer); | ||||||
|  |                 return ReturnObject(Answer); | ||||||
|  |             } | ||||||
| 	        BadRequest(RESTAPI::Errors::InvalidCommand); | 	        BadRequest(RESTAPI::Errors::InvalidCommand); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| @@ -4400,7 +4481,7 @@ namespace OpenWifi { | |||||||
|                                                Path, |                                                Path, | ||||||
|                                                Poco::Net::HTTPMessage::HTTP_1_1); |                                                Poco::Net::HTTPMessage::HTTP_1_1); | ||||||
|  |  | ||||||
|                 Poco::Logger::get("REST-CALLER-GET").debug(fmt::format(" {}", URI.toString())); |                 poco_debug(Poco::Logger::get("REST-CALLER-GET"),fmt::format(" {}", URI.toString())); | ||||||
|  |  | ||||||
|                 if(BearerToken.empty()) { |                 if(BearerToken.empty()) { | ||||||
|                     Request.add("X-API-KEY", Svc.AccessKey); |                     Request.add("X-API-KEY", Svc.AccessKey); | ||||||
| @@ -4458,7 +4539,7 @@ namespace OpenWifi { | |||||||
|                 for (const auto &qp : QueryData_) |                 for (const auto &qp : QueryData_) | ||||||
|                     URI.addQueryParameter(qp.first, qp.second); |                     URI.addQueryParameter(qp.first, qp.second); | ||||||
|  |  | ||||||
|                 Poco::Logger::get("REST-CALLER-PUT").debug(fmt::format("{}", URI.toString())); |                 poco_debug(Poco::Logger::get("REST-CALLER-PUT"),fmt::format("{}", URI.toString())); | ||||||
|  |  | ||||||
|                 std::string Path(URI.getPathAndQuery()); |                 std::string Path(URI.getPathAndQuery()); | ||||||
|  |  | ||||||
| @@ -4537,7 +4618,7 @@ namespace OpenWifi { | |||||||
|                 for (const auto &qp : QueryData_) |                 for (const auto &qp : QueryData_) | ||||||
|                     URI.addQueryParameter(qp.first, qp.second); |                     URI.addQueryParameter(qp.first, qp.second); | ||||||
|  |  | ||||||
|                 Poco::Logger::get("REST-CALLER-POST").debug(fmt::format(" {}", URI.toString())); |                 poco_debug(Poco::Logger::get("REST-CALLER-POST"),fmt::format(" {}", URI.toString())); | ||||||
|  |  | ||||||
|                 std::string Path(URI.getPathAndQuery()); |                 std::string Path(URI.getPathAndQuery()); | ||||||
|  |  | ||||||
| @@ -4613,7 +4694,7 @@ namespace OpenWifi { | |||||||
|                 for (const auto &qp : QueryData_) |                 for (const auto &qp : QueryData_) | ||||||
|                     URI.addQueryParameter(qp.first, qp.second); |                     URI.addQueryParameter(qp.first, qp.second); | ||||||
|  |  | ||||||
|                 Poco::Logger::get("REST-CALLER-DELETE").debug(fmt::format(" {}", URI.toString())); |                 poco_debug(Poco::Logger::get("REST-CALLER-DELETE"),fmt::format(" {}", URI.toString())); | ||||||
|  |  | ||||||
|                 std::string Path(URI.getPathAndQuery()); |                 std::string Path(URI.getPathAndQuery()); | ||||||
|  |  | ||||||
| @@ -4670,6 +4751,7 @@ namespace OpenWifi { | |||||||
|     inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) { |     inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) { | ||||||
|         if(Internal_ && Request->has("X-INTERNAL-NAME")) { |         if(Internal_ && Request->has("X-INTERNAL-NAME")) { | ||||||
|             auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); |             auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); | ||||||
|  | 			Contacted = true; | ||||||
|             if(!Allowed) { |             if(!Allowed) { | ||||||
|                 if(Server_.LogBadTokens(false)) { |                 if(Server_.LogBadTokens(false)) { | ||||||
|                     Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}", |                     Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}", | ||||||
| @@ -4678,6 +4760,7 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 auto Id = Request->get("X-INTERNAL-NAME", "unknown"); |                 auto Id = Request->get("X-INTERNAL-NAME", "unknown"); | ||||||
|  | 				REST_Requester_ = Id; | ||||||
|                 if(Server_.LogIt(Request->getMethod(),true)) { |                 if(Server_.LogIt(Request->getMethod(),true)) { | ||||||
|                     Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}", |                     Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}", | ||||||
|                                                Utils::FormatIPv6(Request->clientAddress().toString()), Id, |                                                Utils::FormatIPv6(Request->clientAddress().toString()), Id, | ||||||
| @@ -4701,6 +4784,7 @@ namespace OpenWifi { | |||||||
| #else | #else | ||||||
|             if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) { |             if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) { | ||||||
| #endif | #endif | ||||||
|  | 				REST_Requester_ = UserInfo_.userinfo.email; | ||||||
|                 if(Server_.LogIt(Request->getMethod(),true)) { |                 if(Server_.LogIt(Request->getMethod(),true)) { | ||||||
|                     Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}", |                     Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}", | ||||||
|                                                UserInfo_.userinfo.email, |                                                UserInfo_.userinfo.email, | ||||||
| @@ -4818,7 +4902,7 @@ namespace OpenWifi { | |||||||
| 		[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); | 		[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); | ||||||
| 		void SendToAll(const std::string &Payload); | 		void SendToAll(const std::string &Payload); | ||||||
|     private: |     private: | ||||||
|         std::atomic_bool Running_ = false; |         mutable std::atomic_bool Running_ = false; | ||||||
|         Poco::Thread 								Thr_; |         Poco::Thread 								Thr_; | ||||||
|         // std::unique_ptr<MyParallelSocketReactor> ReactorPool_; |         // std::unique_ptr<MyParallelSocketReactor> ReactorPool_; | ||||||
| 		Poco::Net::SocketReactor					Reactor_; | 		Poco::Net::SocketReactor					Reactor_; | ||||||
| @@ -4909,12 +4993,13 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload); |     [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload); | ||||||
|     inline WebSocketClientServer::WebSocketClientServer() noexcept: |     inline WebSocketClientServer::WebSocketClientServer() noexcept: | ||||||
|             SubSystemServer("WebSocketClientServer", "WSCLNT-SVR", "websocketclients") |             SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients") | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void WebSocketClientServer::run() { |     inline void WebSocketClientServer::run() { | ||||||
|         Running_ = true ; |         Running_ = true ; | ||||||
|  | 		Utils::SetThreadName("ws:uiclnt-svr"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(2000); |             Poco::Thread::trySleep(2000); | ||||||
|  |  | ||||||
| @@ -4962,8 +5047,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         for(const auto &client:Clients_) { |         for(const auto &client:Clients_) { | ||||||
|             if(client.second.second == UserName) { |             if(client.second.second == UserName) { | ||||||
|  | 				try { | ||||||
| 					if (client.second.first->Send(Payload)) | 					if (client.second.first->Send(Payload)) | ||||||
| 						Sent++; | 						Sent++; | ||||||
|  | 				} catch (...) { | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return Sent>0; |         return Sent>0; | ||||||
| @@ -4985,6 +5074,7 @@ namespace OpenWifi { | |||||||
|         int flags; |         int flags; | ||||||
|         int n; |         int n; | ||||||
|         bool Done=false; |         bool Done=false; | ||||||
|  | 		try { | ||||||
| 			Poco::Buffer<char> IncomingFrame(0); | 			Poco::Buffer<char> IncomingFrame(0); | ||||||
| 			n = WS_->receiveFrame(IncomingFrame, flags); | 			n = WS_->receiveFrame(IncomingFrame, flags); | ||||||
| 			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; | 			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; | ||||||
| @@ -4998,23 +5088,21 @@ namespace OpenWifi { | |||||||
| 				WS_->sendFrame("", 0, | 				WS_->sendFrame("", 0, | ||||||
| 							   (int)Poco::Net::WebSocket::FRAME_OP_PONG | | 							   (int)Poco::Net::WebSocket::FRAME_OP_PONG | | ||||||
| 								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); | 								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); | ||||||
|             } | 			} break; | ||||||
|                 break; |  | ||||||
| 			case Poco::Net::WebSocket::FRAME_OP_PONG: { | 			case Poco::Net::WebSocket::FRAME_OP_PONG: { | ||||||
|             } | 			} break; | ||||||
|                 break; |  | ||||||
| 			case Poco::Net::WebSocket::FRAME_OP_CLOSE: { | 			case Poco::Net::WebSocket::FRAME_OP_CLOSE: { | ||||||
|                 Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_)); | 				Logger().warning(Poco::format("CLOSE(%s): UI Client is closing its connection.", Id_)); | ||||||
| 				Done = true; | 				Done = true; | ||||||
|             } | 			} break; | ||||||
|                 break; |  | ||||||
| 			case Poco::Net::WebSocket::FRAME_OP_TEXT: { | 			case Poco::Net::WebSocket::FRAME_OP_TEXT: { | ||||||
| 				IncomingFrame.append(0); | 				IncomingFrame.append(0); | ||||||
| 				if (!Authenticated_) { | 				if (!Authenticated_) { | ||||||
| 					std::string Frame{IncomingFrame.begin()}; | 					std::string Frame{IncomingFrame.begin()}; | ||||||
| 					auto Tokens = Utils::Split(Frame, ':'); | 					auto Tokens = Utils::Split(Frame, ':'); | ||||||
| 					bool Expired = false, Contacted = false; | 					bool Expired = false, Contacted = false; | ||||||
|                     if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | 					if (Tokens.size() == 2 && | ||||||
|  | 						AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | ||||||
| 						Authenticated_ = true; | 						Authenticated_ = true; | ||||||
| 						std::string S{"Welcome! Bienvenue! Bienvenidos!"}; | 						std::string S{"Welcome! Bienvenue! Bienvenidos!"}; | ||||||
| 						WS_->sendFrame(S.c_str(), S.size()); | 						WS_->sendFrame(S.c_str(), S.size()); | ||||||
| @@ -5028,8 +5116,8 @@ namespace OpenWifi { | |||||||
| 				} else { | 				} else { | ||||||
| 					try { | 					try { | ||||||
| 						Poco::JSON::Parser P; | 						Poco::JSON::Parser P; | ||||||
|                         auto Obj = P.parse(IncomingFrame.begin()) | 						auto Obj = | ||||||
|                                 .extract<Poco::JSON::Object::Ptr>(); | 							P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>(); | ||||||
| 						std::string Answer; | 						std::string Answer; | ||||||
| 						if (Processor_ != nullptr) | 						if (Processor_ != nullptr) | ||||||
| 							Processor_->Processor(Obj, Answer, Done); | 							Processor_->Processor(Obj, Answer, Done); | ||||||
| @@ -5040,14 +5128,15 @@ namespace OpenWifi { | |||||||
| 						} | 						} | ||||||
| 					} catch (const Poco::JSON::JSONException &E) { | 					} catch (const Poco::JSON::JSONException &E) { | ||||||
| 						Logger().log(E); | 						Logger().log(E); | ||||||
|  | 						Done=true; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 			} break; | ||||||
|  | 			default: { | ||||||
| 			} | 			} | ||||||
|                 break; |  | ||||||
|             default: |  | ||||||
|             { |  | ||||||
|  |  | ||||||
| 			} | 			} | ||||||
|  | 		} catch (...) { | ||||||
|  | 			Done=true; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if(Done) { |         if(Done) { | ||||||
| @@ -5142,7 +5231,7 @@ namespace OpenWifi { | |||||||
|                 try |                 try | ||||||
|                 { |                 { | ||||||
|                     Poco::Net::WebSocket WS(*Request, *Response); |                     Poco::Net::WebSocket WS(*Request, *Response); | ||||||
|                     Logger().information("WebSocket connection established."); |                     Logger().information("UI-WebSocket connection established."); | ||||||
|                     auto Id = MicroService::CreateUUID(); |                     auto Id = MicroService::CreateUUID(); | ||||||
|                     WebSocketClientServer()->NewClient(WS,Id); |                     WebSocketClientServer()->NewClient(WS,Id); | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -133,6 +133,37 @@ namespace ORM { | |||||||
|         return R; |         return R; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     inline std::string WHERE_AND_(std::string Result) { | ||||||
|  |         return Result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) { | ||||||
|  |         if constexpr(std::is_same_v<T,std::string>) | ||||||
|  |         { | ||||||
|  |             if(!Value.empty()) { | ||||||
|  |                 if(!Result.empty()) | ||||||
|  |                     Result += " and "; | ||||||
|  |                 Result += fieldName; | ||||||
|  |                 Result += '='; | ||||||
|  |                 Result += "'"; | ||||||
|  |                 Result += Escape(Value); | ||||||
|  |                 Result += "'"; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if(!Result.empty()) | ||||||
|  |                 Result += " and "; | ||||||
|  |             Result += fieldName ; | ||||||
|  |             Result += '='; | ||||||
|  |             Result += std::to_string(Value); | ||||||
|  |         } | ||||||
|  |         return WHERE_AND_(Result,args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <typename... Args> std::string WHERE_AND(Args... args) { | ||||||
|  |         std::string Result; | ||||||
|  |         return WHERE_AND_(Result, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; |     enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; | ||||||
|     enum SqlBinaryOp { AND = 0 , OR }; |     enum SqlBinaryOp { AND = 0 , OR }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <cstring> | ||||||
| #include "Poco/String.h" | #include "Poco/String.h" | ||||||
|  |  | ||||||
| #if defined(__GNUC__) | #if defined(__GNUC__) | ||||||
| @@ -428,6 +429,7 @@ namespace OpenWifi::uCentralProtocol { | |||||||
| 	static const char *RADIUSACCT = "acct"; | 	static const char *RADIUSACCT = "acct"; | ||||||
| 	static const char *RADIUSAUTH = "auth"; | 	static const char *RADIUSAUTH = "auth"; | ||||||
| 	static const char *RADIUSDST = "dst"; | 	static const char *RADIUSDST = "dst"; | ||||||
|  | 	static const char *IES = "ies"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| namespace OpenWifi::uCentralProtocol::Events { | namespace OpenWifi::uCentralProtocol::Events { | ||||||
| @@ -457,25 +459,28 @@ namespace OpenWifi::uCentralProtocol::Events { | |||||||
| 		ET_TELEMETRY | 		ET_TELEMETRY | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline static EVENT_MSG EventFromString(const std::string & Method) { | 	inline EVENT_MSG EventFromString(const std::string & Method) { | ||||||
|         static std::vector<std::pair<const char *,EVENT_MSG>>   Values{ | 		if(strcmp(STATE,Method.c_str())==0) | ||||||
|                 { CFGPENDING , ET_CFGPENDING }, | 			return ET_STATE; | ||||||
|                 { CONNECT, ET_CONNECT }, | 		else if(strcmp(HEALTHCHECK,Method.c_str())==0) | ||||||
|                 { CRASHLOG, ET_CRASHLOG }, | 			return ET_HEALTHCHECK; | ||||||
|                 { DEVICEUPDATE, ET_DEVICEUPDATE }, | 		else if(strcmp(CONNECT,Method.c_str())==0) | ||||||
|                 { HEALTHCHECK, ET_HEALTHCHECK }, | 			return ET_CONNECT; | ||||||
|                 { LOG, ET_LOG }, | 		else if(strcmp(CFGPENDING,Method.c_str())==0) | ||||||
|                 { PING, ET_PING }, | 			return ET_CFGPENDING; | ||||||
|                 { RECOVERY, ET_RECOVERY }, | 		else if(strcmp(CRASHLOG,Method.c_str())==0) | ||||||
|                 { STATE, ET_STATE }, | 			return ET_CRASHLOG; | ||||||
|                 { TELEMETRY, ET_TELEMETRY } | 		else if(strcmp(DEVICEUPDATE,Method.c_str())==0) | ||||||
|         }; | 			return ET_DEVICEUPDATE; | ||||||
|  | 		else if(strcmp(LOG,Method.c_str())==0) | ||||||
|         std::string L = Poco::toLower(Method); | 			return ET_LOG; | ||||||
|         auto hint = std::find_if(cbegin(Values),cend(Values),[&](const std::pair<const char *,EVENT_MSG> &v) ->bool { return strcmp(v.first,L.c_str())==0; }); | 		else if(strcmp(PING,Method.c_str())==0) | ||||||
|         if(hint == cend(Values)) | 			return ET_PING; | ||||||
|  | 		else if(strcmp(RECOVERY,Method.c_str())==0) | ||||||
|  | 			return ET_RECOVERY; | ||||||
|  | 		else if(strcmp(TELEMETRY,Method.c_str())==0) | ||||||
|  | 			return ET_TELEMETRY; | ||||||
| 		return ET_UNKNOWN; | 		return ET_UNKNOWN; | ||||||
|         return hint->second; |  | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     static std::string MakeSessionId(const std::string & token) { |     static std::string MakeSessionId(const std::string & token) { | ||||||
|         return MicroService::instance().CreateHash(token); |         return Utils::ComputeHash(token); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void LoginDB::AddLogin( const std::string & userId, const std::string & email, const std::string &token) { |     void LoginDB::AddLogin( const std::string & userId, const std::string & email, const std::string &token) { | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								templates/email_invitation.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								templates/email_invitation.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>eMail Invitation</title> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										7
									
								
								templates/email_invitation.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								templates/email_invitation.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | Dear ${RECIPIENT_EMAIL}, | ||||||
|  |  | ||||||
|  |     You have been invited to join the OpenWifi system. Please click below and follow the instructions | ||||||
|  |  | ||||||
|  |         ${ACTION_LINK} | ||||||
|  |  | ||||||
|  | Thank you! | ||||||
| @@ -2,7 +2,10 @@ | |||||||
| <html lang="en"> | <html lang="en"> | ||||||
| <head> | <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <title>Title</title> |     <title>eMail Verification</title> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,16 @@ | |||||||
| <html lang="en"> | <html lang="en"> | ||||||
| <head> | <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <title>Title</title> |     <title>Password Reset</title> | ||||||
|  |  | ||||||
|  |     <form action="${ACTION_LINK_HTML}"> | ||||||
|  |         <label for="fname">First name: </label> | ||||||
|  |         <input type="text" id="fname" name="fname"><br><br> | ||||||
|  |         <label for="lname">Last name: </label> | ||||||
|  |         <input type="text" id="lname" name="lname"><br><br> | ||||||
|  |         <input type="submit" value="Submit"> | ||||||
|  |     </form> | ||||||
|  |  | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										441
									
								
								templates/sample.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										441
									
								
								templates/sample.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,441 @@ | |||||||
|  | <!doctype html><html><head> | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width"> | ||||||
|  |     <title>Project Groups now available to join - Telecom Infra Project</title> | ||||||
|  |         <style> | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         GLOBAL RESETS | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         /*All the styling goes here*/ | ||||||
|  |         img { | ||||||
|  |         border: none; | ||||||
|  |         -ms-interpolation-mode: bicubic; | ||||||
|  |         max-width: 100%; | ||||||
|  |         } | ||||||
|  |         body { | ||||||
|  |         color: #414141; | ||||||
|  |         background-color: #f6f6f6; | ||||||
|  |         font-family: sans-serif; | ||||||
|  |         -webkit-font-smoothing: antialiased; | ||||||
|  |         font-size: 14px; | ||||||
|  |         line-height: 1.4; | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 0; | ||||||
|  |         -ms-text-size-adjust: 100%; | ||||||
|  |         -webkit-text-size-adjust: 100%; | ||||||
|  |         } | ||||||
|  |         table { | ||||||
|  |         border-collapse: separate; | ||||||
|  |         mso-table-lspace: 0pt; | ||||||
|  |         mso-table-rspace: 0pt; | ||||||
|  |         width: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |         } | ||||||
|  |         table td { | ||||||
|  |         font-family: sans-serif; | ||||||
|  |         font-size: 14px; | ||||||
|  |         color: #414141; | ||||||
|  |         vertical-align: top; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         BODY & CONTAINER | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         .body { | ||||||
|  |         background-color: white; | ||||||
|  |         width: 100%; | ||||||
|  |         } | ||||||
|  |         /* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something | ||||||
|  |         */ | ||||||
|  |         .container { | ||||||
|  |         display: block; | ||||||
|  |         margin: 0 auto !important; | ||||||
|  |         /* makes it centered */ | ||||||
|  |         max-width: 580px; | ||||||
|  |         padding: 10px; | ||||||
|  |         width: 580px; | ||||||
|  |         } | ||||||
|  |         /* This should also be a block element, so that it will fill 100% of the container */ | ||||||
|  |         .content { | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         display: block; | ||||||
|  |         margin: 0 auto; | ||||||
|  |         max-width: 580px; | ||||||
|  |         padding: 10px; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         HEADER, FOOTER, MAIN | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         .main { | ||||||
|  |         background: #ffffff; | ||||||
|  |         border-radius: 0px; | ||||||
|  |         width: 600px; | ||||||
|  |         max-width: 100%; | ||||||
|  |         border: 1px solid #d4d4d4; | ||||||
|  |         padding-left: 45px; | ||||||
|  |         padding-right: 45px; | ||||||
|  |         } | ||||||
|  |         .wrapper { | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         padding: 40px 20px; | ||||||
|  |         } | ||||||
|  |         .content-block { | ||||||
|  |         padding-bottom: 10px; | ||||||
|  |         padding-top: 10px; | ||||||
|  |         } | ||||||
|  |         .footer { | ||||||
|  |         clear: both; | ||||||
|  |         margin-top: 10px; | ||||||
|  |         text-align: center; | ||||||
|  |         width: 100%; | ||||||
|  |         } | ||||||
|  |         .footer td, | ||||||
|  |         .footer p, | ||||||
|  |         .footer span, | ||||||
|  |         .footer a { | ||||||
|  |         color: #999999; | ||||||
|  |         font-size: 12px; | ||||||
|  |         text-align: center; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         TYPOGRAPHY | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         h1, | ||||||
|  |         h2, | ||||||
|  |         h3, | ||||||
|  |         h4 { | ||||||
|  |         color: #414141; | ||||||
|  |         font-family: sans-serif; | ||||||
|  |         font-weight: 400; | ||||||
|  |         line-height: 1.4; | ||||||
|  |         margin: 0; | ||||||
|  |         margin-bottom: 30px; | ||||||
|  |         } | ||||||
|  |         h2 { | ||||||
|  |         font-weight: 600; | ||||||
|  |         } | ||||||
|  |         h1 { | ||||||
|  |         font-size: 35px; | ||||||
|  |         font-weight: 300; | ||||||
|  |         text-align: center; | ||||||
|  |         text-transform: capitalize; | ||||||
|  |         } | ||||||
|  |         p, | ||||||
|  |         ul, | ||||||
|  |         ol { | ||||||
|  |         font-family: sans-serif; | ||||||
|  |         font-size: 14px; | ||||||
|  |         font-weight: normal; | ||||||
|  |         margin: 0; | ||||||
|  |         color: #414141; | ||||||
|  |         margin-bottom: 15px; | ||||||
|  |         } | ||||||
|  |         p li, | ||||||
|  |         ul li, | ||||||
|  |         ol li { | ||||||
|  |         list-style-position: inside; | ||||||
|  |         margin-left: 5px; | ||||||
|  |         color: #414141; | ||||||
|  |         } | ||||||
|  |         a { | ||||||
|  |         color: #29818c !important; | ||||||
|  |         text-decoration: none; | ||||||
|  |         border-bottom: 1px solid #d2d2d2; | ||||||
|  |         } | ||||||
|  |         .footer a { | ||||||
|  |         color: #999999 !important; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         BUTTONS | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         .btn { | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         width: 100%; | ||||||
|  |         } | ||||||
|  |         tbody { | ||||||
|  |         text-align: left; | ||||||
|  |         } | ||||||
|  |         .btn > tbody > tr > td { | ||||||
|  |         padding-bottom: 15px; | ||||||
|  |         } | ||||||
|  |         .btn table { | ||||||
|  |         width: auto; | ||||||
|  |         } | ||||||
|  |         .btn table td { | ||||||
|  |         background-color: #ffffff; | ||||||
|  |         border-radius: 20px; | ||||||
|  |         text-align: center; | ||||||
|  |         } | ||||||
|  |         .btn a { | ||||||
|  |         background-color: #ffffff; | ||||||
|  |         border: solid 1px #489e94; | ||||||
|  |         border-radius: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         color: #29818c; | ||||||
|  |         cursor: pointer; | ||||||
|  |         display: inline-block; | ||||||
|  |         font-size: 14px; | ||||||
|  |         font-weight: bold; | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 12px 120px; | ||||||
|  |         text-decoration: none; | ||||||
|  |         font-weight:600; | ||||||
|  |         text-transform: uppercase; | ||||||
|  |         } | ||||||
|  |         .btn-primary table td { | ||||||
|  |         /*  background-color: #29818c;*/ | ||||||
|  |         } | ||||||
|  |         .btn-primary a { | ||||||
|  |         transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, | ||||||
|  |         box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, | ||||||
|  |         border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; | ||||||
|  |         margin: auto; | ||||||
|  |         background-color: #29818c; | ||||||
|  |         border-color: #29818c; | ||||||
|  |         color: #ffffff !important; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         OTHER STYLES THAT MIGHT BE USEFUL | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         .last { | ||||||
|  |         margin-bottom: 0; | ||||||
|  |         } | ||||||
|  |         .first { | ||||||
|  |         margin-top: 0; | ||||||
|  |         } | ||||||
|  |         .align-center { | ||||||
|  |         text-align: center; | ||||||
|  |         } | ||||||
|  |         .align-right { | ||||||
|  |         text-align: right; | ||||||
|  |         } | ||||||
|  |         .align-left { | ||||||
|  |         text-align: left; | ||||||
|  |         } | ||||||
|  |         .clear { | ||||||
|  |         clear: both; | ||||||
|  |         } | ||||||
|  |         .mt0 { | ||||||
|  |         margin-top: 0; | ||||||
|  |         } | ||||||
|  |         .mb0 { | ||||||
|  |         margin-bottom: 0; | ||||||
|  |         } | ||||||
|  |         .preheader { | ||||||
|  |         color: transparent; | ||||||
|  |         display: none; | ||||||
|  |         height: 0; | ||||||
|  |         max-height: 0; | ||||||
|  |         max-width: 0; | ||||||
|  |         opacity: 0; | ||||||
|  |         overflow: hidden; | ||||||
|  |         mso-hide: all; | ||||||
|  |         visibility: hidden; | ||||||
|  |         width: 0; | ||||||
|  |         } | ||||||
|  |         .powered-by a { | ||||||
|  |         text-decoration: none; | ||||||
|  |         } | ||||||
|  |         hr { | ||||||
|  |         border: 0; | ||||||
|  |         border-bottom: 1px solid #d4d4d4; | ||||||
|  |         margin: 20px 0; | ||||||
|  |         } | ||||||
|  |         .grayFont { | ||||||
|  |         color: #999999; | ||||||
|  |         } | ||||||
|  |         .bold { | ||||||
|  |         font-weight: 600; | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         RESPONSIVE AND MOBILE FRIENDLY STYLES | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         @media only screen and (max-width: 620px) { | ||||||
|  |         table[class="body"] h1 { | ||||||
|  |         font-size: 28px !important; | ||||||
|  |         margin-bottom: 10px !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] p, | ||||||
|  |         table[class="body"] ul, | ||||||
|  |         table[class="body"] ol, | ||||||
|  |         table[class="body"] td, | ||||||
|  |         table[class="body"] span, | ||||||
|  |         table[class="body"] a { | ||||||
|  |         font-size: 16px !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .wrapper, | ||||||
|  |         table[class="body"] .article { | ||||||
|  |         padding: 10px !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .content { | ||||||
|  |         padding: 0 !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .container { | ||||||
|  |         padding: 0 !important; | ||||||
|  |         width: 100% !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .main { | ||||||
|  |         border-left-width: 0 !important; | ||||||
|  |         border-radius: 0 !important; | ||||||
|  |         border-right-width: 0 !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .btn table { | ||||||
|  |         width: 100% !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .btn a { | ||||||
|  |         width: 100% !important; | ||||||
|  |         } | ||||||
|  |         table[class="body"] .img-responsive { | ||||||
|  |         height: auto !important; | ||||||
|  |         max-width: 100% !important; | ||||||
|  |         width: auto !important; | ||||||
|  |         } | ||||||
|  |         } | ||||||
|  |         /* ------------------------------------- | ||||||
|  |         PRESERVE THESE STYLES IN THE HEAD | ||||||
|  |         ------------------------------------- */ | ||||||
|  |         @media all { | ||||||
|  |         .ExternalClass { | ||||||
|  |         width: 100%; | ||||||
|  |         } | ||||||
|  |         .ExternalClass, | ||||||
|  |         .ExternalClass p, | ||||||
|  |         .ExternalClass span, | ||||||
|  |         .ExternalClass font, | ||||||
|  |         .ExternalClass td, | ||||||
|  |         .ExternalClass div { | ||||||
|  |         line-height: 100%; | ||||||
|  |         } | ||||||
|  |         .apple-link a { | ||||||
|  |         color: inherit !important; | ||||||
|  |         font-family: inherit !important; | ||||||
|  |         font-size: inherit !important; | ||||||
|  |         font-weight: inherit !important; | ||||||
|  |         line-height: inherit !important; | ||||||
|  |         text-decoration: none !important; | ||||||
|  |         } | ||||||
|  |         .btn-primary table td:hover { | ||||||
|  |         /* background-color: rgb(50, 110, 103) !important; */ | ||||||
|  |         } | ||||||
|  |         .btn-primary a:hover { | ||||||
|  |         background-color: rgb(50, 110, 103) !important; | ||||||
|  |         border-color: rgb(50, 110, 103) !important; | ||||||
|  |         } | ||||||
|  |         } | ||||||
|  |         </style> | ||||||
|  |         </head> | ||||||
|  |         <body class=""> | ||||||
|  |         <span class="preheader"></span> | ||||||
|  |         <table d="" role="presentation" border="0" cellpadding="0" cellspacing="0" class="body"> | ||||||
|  |         <tr> | ||||||
|  |         <td> </td> | ||||||
|  |         <td class="container"> | ||||||
|  |         <div class="content"> | ||||||
|  |         <!-- START CENTERED WHITE CONTAINER --> | ||||||
|  |         <table border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width:100%"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <td valign="top" style="padding:0px"> | ||||||
|  |         <table align="left" width="100%" border="0" cellpadding="0" cellspacing="0" style="min-width:100%"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <td valign="top" style="padding-right:0px;padding-left:0px;padding-top:0;padding-bottom:0;text-align:center"> | ||||||
|  |         <img align="center" alt="Telecom Infra Project" src="https://gallery.mailchimp.com/d068b19c9ce4cd81f132f1844/images/f4ac7418-c41c-4aee-890b-efe01f3302cb.png" | ||||||
|  |              width="600" style="max-width:100%;padding-bottom:0;display:inline!important;vertical-align:bottom"> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         <table role="presentation" class="main"> | ||||||
|  |         <!-- START MAIN CONTENT AREA --> | ||||||
|  |         <tr> | ||||||
|  |         <td class="wrapper"> | ||||||
|  |         <table role="presentation" border="0" cellpadding="0" cellspacing="0"> | ||||||
|  |         <tr> | ||||||
|  |         <td> | ||||||
|  |         <h2>Project Groups now available to join - Telecom Infra Project</h2> | ||||||
|  |         <p>Dear Jaspreet Sachdev,</p> | ||||||
|  |         <p> | ||||||
|  |         Facebook is now a member of the following TIP Project Group, | ||||||
|  |         which means they are available for you to join: | ||||||
|  |         </p> | ||||||
|  |         <p> | ||||||
|  |         <ul style="text-align: left;margin: auto;display: inline-block;"> | ||||||
|  |         <li><a href="https://urldefense.com/" target="_blank">Wi-Fi</a></li> | ||||||
|  |         </ul> | ||||||
|  |         </p> | ||||||
|  |         <p> | ||||||
|  |         If you would like to participate in any of these groups, you may join | ||||||
|  |         by logging in to your TIP Membership Account and navigating to My Project | ||||||
|  |         Groups. | ||||||
|  |         </p> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         <tr> | ||||||
|  |         <table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <td> | ||||||
|  |         <table role="presentation" border="0" cellpadding="0" cellspacing="0"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <td> | ||||||
|  |         <a href="https://urldefense.com/v3/" target="_blank">Account Login</a> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         </tr> | ||||||
|  |         <tr> | ||||||
|  |         <td> | ||||||
|  |         <p>Questions? <a href="https://urldefense.com/v3/" target="_blank">Contact TIP Support</a> or email support@telecominfraproject.com.</p> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         <tr> | ||||||
|  |         <td> | ||||||
|  |         <p>Sincerely,</p> | ||||||
|  |         <p>Telecom Infra Project</p> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </table> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         <!-- END MAIN CONTENT AREA --> | ||||||
|  |         </table> | ||||||
|  |         =09 | ||||||
|  |         <!-- END CENTERED WHITE CONTAINER --> | ||||||
|  |         <div class="footer"> | ||||||
|  |         <table border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width:100;margin-top:30px;"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <td valign="top" style="padding:0px"> | ||||||
|  |         <table align="left" width="100%" border="0" cellpadding="0" cellspacing="0" style="min-width:100%"> | ||||||
|  |         <tbody> | ||||||
|  |         <tr> | ||||||
|  |         <tr> | ||||||
|  |         <p style="text-align:center"> | ||||||
|  |         Copyright =C2=A9 2021 Telecom Infra Project, All rights reserved. | ||||||
|  |         </p> | ||||||
|  |         <a href="https://urldefense.com/v3/" target="_blank">www.telecominfraproject.com</a> | ||||||
|  |         </tr> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         </td> | ||||||
|  |         </tr> | ||||||
|  |         </tbody> | ||||||
|  |         </table> | ||||||
|  |         </div> | ||||||
|  |         </div> | ||||||
|  |         </td> | ||||||
|  |         <td> </td> | ||||||
|  |         </tr> | ||||||
|  |         </table> | ||||||
|  |         <img src="https://mandrillapp.com/track/open.php?u=31039844&id=6424f96bfb88484685c7229756fee3fb" height="1" width="1"></body> | ||||||
|  |         </html> | ||||||
							
								
								
									
										0
									
								
								templates/sub_email_verification.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_email_verification.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/sub_email_verification.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_email_verification.txt
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/sub_password_reset.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_password_reset.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/sub_password_reset.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_password_reset.txt
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/sub_verification_code.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_verification_code.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/sub_verification_code.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/sub_verification_code.txt
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								templates/verification_code.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/verification_code.html
									
									
									
									
									
										Normal file
									
								
							| @@ -1 +0,0 @@ | |||||||
| null |  | ||||||
| @@ -96,7 +96,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,7 +103,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,7 +103,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|   <div></div> |   <div></div> | ||||||
|   <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |   <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|   <div></div> |   <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								wwwassets/invitation_error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/invitation_error.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/invitation_success.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/invitation_success.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										
											BIN
										
									
								
								wwwassets/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wwwassets/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.8 KiB | 
| @@ -101,7 +101,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -122,7 +122,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,7 +70,7 @@ | |||||||
| <body> | <body> | ||||||
|     <div class="logo-grid"> |     <div class="logo-grid"> | ||||||
|         <div></div> |         <div></div> | ||||||
|         <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |         <div><img src="/wwwassets/logo.png" alt="OpenWifi"></div> | ||||||
|         <div></div> |         <div></div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -122,7 +122,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ | |||||||
|  |  | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ | |||||||
| <body> | <body> | ||||||
| <div class="logo-grid"> | <div class="logo-grid"> | ||||||
|     <div></div> |     <div></div> | ||||||
|     <div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div> |     <div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div> | ||||||
|     <div></div> |     <div></div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								wwwassets/sub_404_error.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_404_error.css
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_404_error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_404_error.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_access_policy.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_access_policy.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_email_verification_error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_email_verification_error.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_email_verification_success.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_email_verification_success.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										
											BIN
										
									
								
								wwwassets/sub_favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wwwassets/sub_favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 202 KiB | 
							
								
								
									
										
											BIN
										
									
								
								wwwassets/sub_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wwwassets/sub_logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										0
									
								
								wwwassets/sub_password_policy.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_password_policy.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_password_reset.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_password_reset.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_password_reset_error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_password_reset_error.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								wwwassets/sub_password_reset_success.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								wwwassets/sub_password_reset_success.html
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user