mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-10-30 10:22:22 +00:00
Compare commits
10 Commits
release/v2
...
release/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
830750f857 | ||
|
|
f8d3079f44 | ||
|
|
81cec762f7 | ||
|
|
f43198f874 | ||
|
|
3134947b57 | ||
|
|
8e8656a6ae | ||
|
|
8863d2ecc9 | ||
|
|
70ddeaf3c1 | ||
|
|
56d7c7c767 | ||
|
|
7e3fb701a0 |
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owsec VERSION 2.7.0)
|
||||
project(owsec VERSION 2.6.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -47,7 +47,6 @@ add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
|
||||
set(BUILD_SHARED_LIBS 1)
|
||||
|
||||
add_definitions(-DTIP_SECURITY_SERVICE="1")
|
||||
add_definitions(-DPOCO_LOG_DEBUG="1")
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
if(ASAN)
|
||||
@@ -78,7 +77,6 @@ add_executable( owsec
|
||||
src/framework/orm.h
|
||||
src/framework/StorageClass.h
|
||||
src/framework/ow_constants.h
|
||||
src/framework/MicroServiceErrorHandler.h
|
||||
src/framework/WebSocketClientNotifications.h
|
||||
src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
|
||||
src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
|
||||
@@ -126,7 +124,7 @@ add_executable( owsec
|
||||
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
|
||||
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
|
||||
src/SpecialUserHelpers.h
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h)
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owsec PUBLIC
|
||||
|
||||
69
Dockerfile
69
Dockerfile
@@ -1,24 +1,16 @@
|
||||
ARG DEBIAN_VERSION=11.4-slim
|
||||
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:3.15 AS build-base
|
||||
|
||||
FROM debian:$DEBIAN_VERSION AS build-base
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||
librdkafka-dev libboost-all-dev libssl-dev \
|
||||
zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev
|
||||
unixodbc-dev postgresql-dev mariadb-dev \
|
||||
librdkafka-dev boost-dev openssl-dev \
|
||||
zlib-dev nlohmann-json \
|
||||
curl-dev
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -29,10 +21,8 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ARG FMTLIB_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
@@ -43,10 +33,8 @@ RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -57,10 +45,8 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -71,19 +57,14 @@ RUN make install
|
||||
|
||||
FROM build-base AS aws-sdk-cpp-build
|
||||
|
||||
ARG AWS_SDK_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
|
||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
|
||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json
|
||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
|
||||
|
||||
WORKDIR /aws-sdk-cpp
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DUSE_OPENSSL=ON \
|
||||
-DCPP_STANDARD=17 \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
|
||||
-DAUTORUN_UNIT_TESTS=OFF
|
||||
RUN cmake --build . --config Release -j8
|
||||
@@ -111,24 +92,26 @@ COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
|
||||
WORKDIR /owsec
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR /owsec/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake .. \
|
||||
-Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
|
||||
-DBUILD_SHARED_LIBS=ON
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM debian:$DEBIAN_VERSION
|
||||
FROM alpine:3.15
|
||||
|
||||
ENV OWSEC_USER=owsec \
|
||||
OWSEC_ROOT=/owsec-data \
|
||||
OWSEC_CONFIG=/owsec-data
|
||||
|
||||
RUN useradd "$OWSEC_USER"
|
||||
RUN addgroup -S "$OWSEC_USER" && \
|
||||
adduser -S -G "$OWSEC_USER" "$OWSEC_USER"
|
||||
|
||||
RUN mkdir /openwifi
|
||||
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
|
||||
chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||
libmariadb-dev-compat libpq5 unixodbc postgresql-client
|
||||
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
|
||||
mariadb-connector-c libpq unixodbc postgresql-client
|
||||
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
@@ -139,7 +122,7 @@ COPY templates /dist/templates
|
||||
COPY docker-entrypoint.sh /
|
||||
COPY wait-for-postgres.sh /
|
||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
|
||||
|
||||
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
|
||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
|
||||
@@ -148,8 +131,6 @@ COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-c
|
||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
|
||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
|
||||
|
||||
RUN ldconfig
|
||||
|
||||
EXPOSE 16001 17001 16101
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
37
OPERATOR.md
37
OPERATOR.md
@@ -1,37 +0,0 @@
|
||||
# Operator Support
|
||||
In order to support multiple tenants and operators, you must prepare the security service to serve
|
||||
customized e-mails and messages.
|
||||
|
||||
## Structure for `templates`
|
||||
Any file in the root of the directory will be used as defaults. The following files must be present:
|
||||
- email_invitation.html/txt : This email message will be sent to a newly added user.
|
||||
- email_verification.html/txt : This email is sent when an email verification is required.
|
||||
- password_reset.html/txt : This is sent when a pasword reset is requested.
|
||||
- verification_code.html/txt : This is used during MFA when email based.
|
||||
- signup_verification.html/txt : This email is send to a new subscriber who signed up for service.
|
||||
- sub_email_verification.html/txt : This is sent to a subscriber requiring an email verification.
|
||||
- sub_verification_code.html/txt : This is used during MFA when email based for a subscriber.
|
||||
- logo.jpg : The default logo to use in any of these emails.
|
||||
|
||||
## Structure for `wwwassets`
|
||||
Any file in the root of the directory will be used as defaults. The following files must be present:
|
||||
- email_verification_error.html : Used when email verification has failed.
|
||||
- email_verification_success.html : Used when emil verification has succeeded.
|
||||
- invitation_error.html :
|
||||
- invitation_success.html :
|
||||
- password_policy.html :
|
||||
- password_reset.html :
|
||||
- password_reset_success.html :
|
||||
- password_reset_error.html :
|
||||
- signup_verification.html :
|
||||
- signup_verification_error.html :
|
||||
- signup_verification_success.html :
|
||||
- favicon.ico : icon for the application
|
||||
- 404_error.html : your customized 404 page
|
||||
- the_logo : the logo to use.
|
||||
|
||||
## For tenants
|
||||
When creating a tenant/operator, you must create a subdirectory inside each `wwwassets` and `templates` and replicate
|
||||
all the files that appear at the root level. You need to use the short Operator name (also known as RegistrantId in the API). This means
|
||||
no spaces, all lowercase characters and numbers. No special characters: 0-9 and a-z.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
@@ -23,7 +23,6 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17001"} \
|
||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16001"} \
|
||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
|
||||
SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \
|
||||
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
|
||||
SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \
|
||||
@@ -85,7 +84,7 @@ if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$RUN_CHOWN" = 'true' ]; then
|
||||
chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
|
||||
fi
|
||||
exec gosu "$OWSEC_USER" "$@"
|
||||
exec su-exec "$OWSEC_USER" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
2
helm/.gitignore
vendored
2
helm/.gitignore
vendored
@@ -1,3 +1 @@
|
||||
*.swp
|
||||
Chart.lock
|
||||
charts/
|
||||
|
||||
@@ -70,8 +70,8 @@ The following table lists the configurable parameters of the chart and their def
|
||||
| persistence.size | string | Defines PV size | `'10Gi'` |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to the Security | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `owsec.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
|
||||
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Security (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted) | |
|
||||
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -47,39 +46,6 @@ spec:
|
||||
- -timeout
|
||||
- 600s
|
||||
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owsec.repository }}:{{ .Values.images.owsec.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owsec.pullPolicy }}
|
||||
command:
|
||||
- /wait-for-postgres.sh
|
||||
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||
- echo
|
||||
- "PostgreSQL is ready"
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
value: "{{ now }}"
|
||||
{{- range $key, $value := .Values.public_env_variables }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.secret_env_variables }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "owsec.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owsec }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
- name: owsec
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owsec:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
|
||||
tag: v2.7.0
|
||||
tag: v2.6.0
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -71,7 +71,7 @@ volumes:
|
||||
mountPath: /owsec-data/certs
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owsec.fullname" . }}-certs{{ end }}
|
||||
secretName: {{ include "owsec.fullname" . }}-certs
|
||||
# Change this if you want to use another volume type
|
||||
- name: persist
|
||||
mountPath: /owsec-data/persist
|
||||
@@ -92,7 +92,7 @@ resources: {}
|
||||
# memory: 128Mi
|
||||
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
fsGroup: 101
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
@@ -228,9 +228,6 @@ configProperties:
|
||||
storage.type.mysql.username: stephb
|
||||
storage.type.mysql.password: snoopy99
|
||||
|
||||
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
|
||||
existingCertsSecret: ""
|
||||
|
||||
certs:
|
||||
# restapi-ca.pem: ""
|
||||
# restapi-cert.pem: ""
|
||||
|
||||
@@ -36,7 +36,6 @@ openwifi.system.data = $OWSEC_ROOT/data
|
||||
openwifi.system.uri.private = https://localhost:17001
|
||||
openwifi.system.uri.public = https://local.dpaas.arilia.com:16001
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.security.restapi.disable = false
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.service.key.password = mypassword
|
||||
@@ -133,4 +132,4 @@ storage.type.mysql.connectiontimeout = 60
|
||||
########################################################################
|
||||
logging.type = file
|
||||
logging.path = $OWSEC_ROOT/logs
|
||||
logging.level = debug
|
||||
logging.level = debug
|
||||
@@ -36,7 +36,6 @@ openwifi.system.data = ${SYSTEM_DATA}
|
||||
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
|
||||
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
|
||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
||||
openwifi.service.key = ${SERVICE_KEY}
|
||||
openwifi.service.key.password = ${SERVICE_KEY_PASSWORD}
|
||||
|
||||
@@ -5,25 +5,21 @@
|
||||
#include "ActionLinkManager.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "MessagingTemplates.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int ActionLinkManager::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
if(!Running_)
|
||||
Thr_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ActionLinkManager::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Running_) {
|
||||
Running_ = false;
|
||||
Thr_.wakeUp();
|
||||
Thr_.join();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void ActionLinkManager::run() {
|
||||
@@ -57,59 +53,44 @@ namespace OpenWifi {
|
||||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
|
||||
StorageService()->ActionLinksDB().CancelAction(i.id);
|
||||
continue;
|
||||
} else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) &&
|
||||
(OpenWifi::Now()-i.created)>(24*60*60)) {
|
||||
StorageService()->ActionLinksDB().CancelAction(i.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(i.action) {
|
||||
case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
|
||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) {
|
||||
poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email));
|
||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
|
||||
Logger().information(fmt::format("Send password reset link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
|
||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) {
|
||||
poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
|
||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) {
|
||||
poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email));
|
||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
|
||||
Logger().information(fmt::format("Send email verification link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
|
||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) {
|
||||
poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email));
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
|
||||
Logger().information(fmt::format("Send subscriber password reset link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
|
||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
|
||||
poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email));
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
|
||||
Logger().information(fmt::format("Send subscriber email verification link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
|
||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
|
||||
poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email));
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::SIGNUP_VERIFICATION)) {
|
||||
Logger().information(fmt::format("Send new subscriber email verification link to {}",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,14 @@ namespace OpenWifi {
|
||||
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
|
||||
/* enum Actions {
|
||||
FORGOT_PASSWORD,
|
||||
VERIFY_EMAIL,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_VERIFY_EMAIL,
|
||||
SUB_SIGNUP
|
||||
};
|
||||
*/
|
||||
static ActionLinkManager * instance() {
|
||||
static auto instance_ = new ActionLinkManager;
|
||||
return instance_;
|
||||
|
||||
@@ -8,21 +8,18 @@
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/KafkaTopics.h"
|
||||
|
||||
#include "Poco/Net/OAuth20Credentials.h"
|
||||
#include "Poco/JWT/Token.h"
|
||||
#include "Poco/JWT/Signer.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "StorageService.h"
|
||||
#include "AuthService.h"
|
||||
|
||||
#include "framework/KafkaTopics.h"
|
||||
|
||||
#include "SMTPMailerService.h"
|
||||
#include "MFAServer.h"
|
||||
#include "MessagingTemplates.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -36,6 +33,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int AuthService::AccessTypeToInt(ACCESS_TYPE T) {
|
||||
switch (T) {
|
||||
case USERNAME: return 1;
|
||||
@@ -48,25 +46,24 @@ namespace OpenWifi {
|
||||
static const std::string DefaultPassword_8_u_l_n_1{"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\.\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"};
|
||||
|
||||
int AuthService::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
Logger().notice("Starting...");
|
||||
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
|
||||
RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600);
|
||||
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
|
||||
|
||||
AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
|
||||
PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
|
||||
AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html");
|
||||
PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html");
|
||||
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1);
|
||||
|
||||
SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1);
|
||||
SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html");
|
||||
SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html");
|
||||
SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html");
|
||||
SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AuthService::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
poco_information(Logger(),"Stopped...");
|
||||
Logger().notice("Stopping...");
|
||||
}
|
||||
|
||||
bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
|
||||
@@ -145,20 +142,18 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
|
||||
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
|
||||
{
|
||||
// std::lock_guard Guard(Mutex_);
|
||||
std::string CallToken;
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Expired = false;
|
||||
|
||||
try {
|
||||
std::string CallToken;
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
CallToken = Auth.getBearerToken();
|
||||
}
|
||||
|
||||
if(CallToken.empty()) {
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,40 +161,35 @@ namespace OpenWifi {
|
||||
uint64_t RevocationDate=0;
|
||||
std::string UserId;
|
||||
if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
|
||||
if(RevocationDate!=0) {
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
if(RevocationDate!=0)
|
||||
return false;
|
||||
}
|
||||
auto now=OpenWifi::Now();
|
||||
Expired = (WT.created_ + WT.expires_in_) < now;
|
||||
if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) {
|
||||
UInfo.webtoken = WT;
|
||||
SessionToken = CallToken;
|
||||
poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
|
||||
bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
|
||||
{
|
||||
// std::lock_guard Guard(Mutex_);
|
||||
|
||||
std::string CallToken;
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Expired = false;
|
||||
try {
|
||||
std::string CallToken;
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
CallToken = Auth.getBearerToken();
|
||||
}
|
||||
|
||||
if(CallToken.empty()) {
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -207,23 +197,20 @@ namespace OpenWifi {
|
||||
uint64_t RevocationDate=0;
|
||||
std::string UserId;
|
||||
if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
|
||||
if(RevocationDate!=0) {
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
if(RevocationDate!=0)
|
||||
return false;
|
||||
}
|
||||
auto now=OpenWifi::Now();
|
||||
Expired = (WT.created_ + WT.expires_in_) < now;
|
||||
if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) {
|
||||
UInfo.webtoken = WT;
|
||||
SessionToken = CallToken;
|
||||
poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -527,6 +514,7 @@ namespace OpenWifi {
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
@@ -576,66 +564,33 @@ namespace OpenWifi {
|
||||
return INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) {
|
||||
auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp,":");
|
||||
if(UInfo.userinfo.signingUp.empty() || OperatorParts.count()!=2) {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
|
||||
Attrs[LOGO] = AuthService::GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Login validation code";
|
||||
Attrs[CHALLENGE_CODE] = Challenge;
|
||||
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs);
|
||||
} else {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
|
||||
Attrs[LOGO] = AuthService::GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Login validation code";
|
||||
Attrs[CHALLENGE_CODE] = Challenge;
|
||||
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs);
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) {
|
||||
bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) {
|
||||
switch (Reason) {
|
||||
|
||||
case MessagingTemplates::FORGOT_PASSWORD: {
|
||||
case FORGOT_PASSWORD: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Password reset link";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
|
||||
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs);
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessagingTemplates::EMAIL_VERIFICATION: {
|
||||
case EMAIL_VERIFICATION: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "e-mail Address Verification";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
|
||||
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs);
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", 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;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -644,43 +599,40 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) {
|
||||
bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) {
|
||||
switch (Reason) {
|
||||
|
||||
case MessagingTemplates::SUB_FORGOT_PASSWORD: {
|
||||
case FORGOT_PASSWORD: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Password reset link";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ;
|
||||
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs);
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessagingTemplates::SUB_EMAIL_VERIFICATION: {
|
||||
case EMAIL_VERIFICATION: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "e-mail Address Verification";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_email_verification&id=" + LinkId ;
|
||||
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs);
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
|
||||
UInfo.waitingForEmailCheck = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MessagingTemplates::SIGNUP_VERIFICATION: {
|
||||
case SIGNUP_VERIFICATION: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Signup e-mail Address Verification";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ;
|
||||
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs);
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "signup_verification.txt", Attrs);
|
||||
UInfo.waitingForEmailCheck = true;
|
||||
}
|
||||
break;
|
||||
@@ -741,8 +693,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// return IsValidSubToken(Token, WebToken, UserInfo, Expired);
|
||||
return false;
|
||||
return IsValidSubToken(Token, WebToken, UserInfo, Expired);
|
||||
}
|
||||
|
||||
bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
@@ -22,8 +20,8 @@
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/ExpireLRUCache.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "MessagingTemplates.h"
|
||||
|
||||
namespace OpenWifi{
|
||||
|
||||
@@ -38,6 +36,12 @@ namespace OpenWifi{
|
||||
CUSTOM
|
||||
};
|
||||
|
||||
enum EMAIL_REASON {
|
||||
FORGOT_PASSWORD,
|
||||
EMAIL_VERIFICATION,
|
||||
SIGNUP_VERIFICATION
|
||||
};
|
||||
|
||||
static ACCESS_TYPE IntToAccessType(int C);
|
||||
static int AccessTypeToInt(ACCESS_TYPE T);
|
||||
|
||||
@@ -49,14 +53,14 @@ namespace OpenWifi{
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
|
||||
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
|
||||
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
||||
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
|
||||
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
|
||||
void Logout(const std::string &token, bool EraseFromCache=true);
|
||||
|
||||
[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
|
||||
[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
|
||||
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
||||
void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
|
||||
@@ -86,12 +90,10 @@ namespace OpenWifi{
|
||||
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
|
||||
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
||||
|
||||
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason);
|
||||
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName);
|
||||
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
|
||||
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
|
||||
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
|
||||
[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code);
|
||||
|
||||
bool DeleteUserFromCache(const std::string &UserName);
|
||||
bool DeleteSubUserFromCache(const std::string &UserName);
|
||||
void RevokeToken(std::string & Token);
|
||||
@@ -156,11 +158,11 @@ namespace OpenWifi{
|
||||
|
||||
inline auto AuthService() { return AuthService::instance(); }
|
||||
|
||||
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , std::uint64_t TID, bool & Expired, bool Sub ) {
|
||||
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) {
|
||||
if(Sub)
|
||||
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired );
|
||||
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired );
|
||||
else
|
||||
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired );
|
||||
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
@@ -22,6 +20,7 @@
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
// Created by stephane bourque on 2021-10-11.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "MFAServer.h"
|
||||
#include "SMSSender.h"
|
||||
#include "SMTPMailerService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "AuthService.h"
|
||||
#include "TotpCache.h"
|
||||
|
||||
@@ -45,7 +44,12 @@ namespace OpenWifi {
|
||||
std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen.";
|
||||
return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
|
||||
} else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
|
||||
return AuthService()->SendEmailChallengeCode(UInfo,Challenge);
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
|
||||
Attrs[LOGO] = AuthService::GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Login validation code";
|
||||
Attrs[CHALLENGE_CODE] = Challenge;
|
||||
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
|
||||
} else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-25.
|
||||
//
|
||||
|
||||
#include "MessagingTemplates.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
} // OpenWifi
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MessagingTemplates {
|
||||
public:
|
||||
static MessagingTemplates & instance() {
|
||||
static auto instance = new MessagingTemplates;
|
||||
return *instance;
|
||||
}
|
||||
|
||||
enum EMAIL_REASON {
|
||||
FORGOT_PASSWORD = 0,
|
||||
EMAIL_VERIFICATION,
|
||||
SIGNUP_VERIFICATION,
|
||||
EMAIL_INVITATION,
|
||||
VERIFICATION_CODE,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_EMAIL_VERIFICATION,
|
||||
SUB_VERIFICATION_CODE
|
||||
};
|
||||
|
||||
static std::string AddOperator(const std::string & filename, const std::string &OperatorName) {
|
||||
if(OperatorName.empty())
|
||||
return "/" + filename;
|
||||
return "/" + OperatorName + "/" + filename;
|
||||
}
|
||||
|
||||
static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") {
|
||||
switch (r) {
|
||||
case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName);
|
||||
case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName);
|
||||
case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName);
|
||||
case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName);
|
||||
case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName);
|
||||
case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName);
|
||||
case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName);
|
||||
case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string Logo(const std::string &OperatorName = "" ) {
|
||||
return AddOperator("logo.jpg", OperatorName);
|
||||
}
|
||||
|
||||
static std::string SubLogo(const std::string &OperatorName = "" ) {
|
||||
return AddOperator("sub_logo.jpg", OperatorName);
|
||||
}
|
||||
|
||||
private:
|
||||
inline const static std::vector<std::string> EmailTemplateNames = {
|
||||
"password_reset",
|
||||
"email_verification",
|
||||
"signup_verification",
|
||||
"email_invitation",
|
||||
"verification_code",
|
||||
"sub_password_reset",
|
||||
"sub_email_verification",
|
||||
"sub_verification_code"
|
||||
};
|
||||
};
|
||||
|
||||
inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); }
|
||||
|
||||
} // OpenWifi
|
||||
|
||||
@@ -23,12 +23,8 @@ namespace OpenWifi {
|
||||
|
||||
if(Action=="password_reset")
|
||||
return RequestResetPassword(Link);
|
||||
else if(Action=="sub_password_reset")
|
||||
return RequestSubResetPassword(Link);
|
||||
else if(Action=="email_verification")
|
||||
return DoEmailVerification(Link);
|
||||
else if(Action=="sub_email_verification")
|
||||
return DoSubEmailVerification(Link);
|
||||
else if(Action=="signup_verification")
|
||||
return DoNewSubVerification(Link);
|
||||
else
|
||||
@@ -40,12 +36,8 @@ namespace OpenWifi {
|
||||
|
||||
if(Action=="password_reset")
|
||||
return CompleteResetPassword();
|
||||
else if(Action=="sub_password_reset")
|
||||
return CompleteResetPassword();
|
||||
else if(Action=="signup_completion")
|
||||
return CompleteSubVerification();
|
||||
else if(Action=="email_invitation")
|
||||
return CompleteEmailInvitation();
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
@@ -207,11 +199,10 @@ namespace OpenWifi {
|
||||
|
||||
// Send the update to the provisioning service
|
||||
Poco::JSON::Object Body;
|
||||
auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":");
|
||||
Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]);
|
||||
Body.set("signupUUID", UInfo.signingUp);
|
||||
OpenAPIRequestPut ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
|
||||
{
|
||||
{"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} ,
|
||||
{"signupUUID", UInfo.signingUp} ,
|
||||
{"operation", "emailVerified"}
|
||||
},
|
||||
Body,30000);
|
||||
@@ -247,8 +238,7 @@ namespace OpenWifi {
|
||||
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.validated = true;
|
||||
UInfo.lastEmailCheck = OpenWifi::Now();
|
||||
@@ -272,16 +262,4 @@ namespace OpenWifi {
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteEmailInvitation() {
|
||||
/// TODO:
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) {
|
||||
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,14 +22,11 @@ namespace OpenWifi {
|
||||
true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
|
||||
void RequestResetPassword(SecurityObjects::ActionLink &Link);
|
||||
void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
|
||||
void CompleteResetPassword();
|
||||
void CompleteSubVerification();
|
||||
void DoEmailVerification(SecurityObjects::ActionLink &Link);
|
||||
void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
|
||||
void DoReturnA404();
|
||||
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
||||
void CompleteEmailInvitation();
|
||||
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
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<
|
||||
RESTAPI_oauth2_handler,
|
||||
RESTAPI_user_handler,
|
||||
|
||||
@@ -13,9 +13,8 @@ namespace OpenWifi {
|
||||
auto UserName = GetParameter("email");
|
||||
auto signupUUID = GetParameter("signupUUID");
|
||||
auto owner = GetParameter("owner");
|
||||
auto operatorName = GetParameter("operatorName");
|
||||
if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
|
||||
Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
|
||||
if(UserName.empty() || signupUUID.empty() || owner.empty()) {
|
||||
Logger().error("Signup requires: email, signupUUID, and owner.");
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo NewSub;
|
||||
NewSub.signingUp = operatorName + ":" + signupUUID;
|
||||
NewSub.signingUp = signupUUID;
|
||||
NewSub.waitingForEmailCheck = true;
|
||||
NewSub.name = UserName;
|
||||
NewSub.modified = OpenWifi::Now();
|
||||
|
||||
@@ -203,10 +203,6 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||
field_to_json(Obj,"kafkaPackets", kafkaPackets);
|
||||
field_to_json(Obj,"locale", locale);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"sessionId", sessionId);
|
||||
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -222,21 +218,6 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_to_json(Obj,"connectedDevices", connectedDevices );
|
||||
}
|
||||
|
||||
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_from_json(Obj,"connectedDevices", connectedDevices );
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"server", Server);
|
||||
@@ -312,6 +293,7 @@ namespace OpenWifi::GWObjects {
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -332,8 +314,6 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"description",description);
|
||||
field_to_json(Obj,"authConfig",authConfig);
|
||||
field_to_json(Obj,"acctConfig",acctConfig);
|
||||
field_to_json(Obj,"coaConfig",coaConfig);
|
||||
field_to_json(Obj,"useByDefault",useByDefault);
|
||||
}
|
||||
|
||||
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -342,8 +322,6 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"description",description);
|
||||
field_from_json(Obj,"authConfig",authConfig);
|
||||
field_from_json(Obj,"acctConfig",acctConfig);
|
||||
field_from_json(Obj,"coaConfig",coaConfig);
|
||||
field_from_json(Obj,"useByDefault",useByDefault);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -351,7 +329,7 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
|
||||
void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"strategy",strategy);
|
||||
field_to_json(Obj,"policy",strategy);
|
||||
field_to_json(Obj,"monitor",monitor);
|
||||
field_to_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_to_json(Obj,"methodParameters",methodParameters);
|
||||
@@ -360,7 +338,7 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"strategy",strategy);
|
||||
field_from_json(Obj,"policy",strategy);
|
||||
field_from_json(Obj,"monitor",monitor);
|
||||
field_from_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_from_json(Obj,"methodParameters",methodParameters);
|
||||
@@ -376,16 +354,6 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"ip",ip);
|
||||
field_to_json(Obj,"port",port);
|
||||
field_to_json(Obj,"weight",weight);
|
||||
field_to_json(Obj,"secret",secret);
|
||||
field_to_json(Obj,"certificate",certificate);
|
||||
field_to_json(Obj,"radsec",radsec);
|
||||
field_to_json(Obj,"radsecPort",radsecPort);
|
||||
field_to_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_to_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_to_json(Obj,"radsecCert",radsecCert);
|
||||
field_to_json(Obj,"radsecKey",radsecKey);
|
||||
field_to_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_to_json(Obj,"ignore",ignore);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -394,16 +362,6 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"ip",ip);
|
||||
field_from_json(Obj,"port",port);
|
||||
field_from_json(Obj,"weight",weight);
|
||||
field_from_json(Obj,"secret",secret);
|
||||
field_from_json(Obj,"certificate",certificate);
|
||||
field_from_json(Obj,"radsec",radsec);
|
||||
field_from_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_from_json(Obj,"radsecPort",radsecPort);
|
||||
field_from_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_from_json(Obj,"radsecCert",radsecCert);
|
||||
field_from_json(Obj,"radsecKey",radsecKey);
|
||||
field_from_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_from_json(Obj,"ignore",ignore);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
|
||||
@@ -38,10 +38,6 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
@@ -75,13 +71,6 @@ namespace OpenWifi::GWObjects {
|
||||
void Print() const;
|
||||
};
|
||||
|
||||
struct DeviceConnectionStatistics {
|
||||
std::uint64_t connectedDevices = 0;
|
||||
std::uint64_t averageConnectionTime = 0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0 ;
|
||||
@@ -227,16 +216,6 @@ namespace OpenWifi::GWObjects {
|
||||
std::string ip;
|
||||
uint16_t port=0;
|
||||
uint64_t weight=0;
|
||||
std::string secret;
|
||||
std::string certificate;
|
||||
bool radsec=false;
|
||||
uint16_t radsecPort=2083;
|
||||
std::string radsecSecret;
|
||||
std::string radsecKey;
|
||||
std::string radsecCert;
|
||||
std::vector<std::string> radsecCacerts;
|
||||
std::vector<std::string> radsecRealms;
|
||||
bool ignore=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -258,8 +237,6 @@ namespace OpenWifi::GWObjects {
|
||||
std::string description;
|
||||
RadiusProxyServerConfig authConfig;
|
||||
RadiusProxyServerConfig acctConfig;
|
||||
RadiusProxyServerConfig coaConfig;
|
||||
bool useByDefault=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-31.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
using OpenWifi::RESTAPI_utils::EmbedDocument;
|
||||
|
||||
#include "RESTAPI_OWLSobjects.h"
|
||||
|
||||
// SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d
|
||||
|
||||
namespace OpenWifi::OWLSObjects {
|
||||
|
||||
void SimulationDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"gateway", gateway);
|
||||
field_to_json(Obj,"certificate", certificate);
|
||||
field_to_json(Obj,"key", key);
|
||||
field_to_json(Obj,"macPrefix", macPrefix);
|
||||
field_to_json(Obj,"deviceType", deviceType);
|
||||
field_to_json(Obj,"devices", devices);
|
||||
field_to_json(Obj,"healthCheckInterval", healthCheckInterval);
|
||||
field_to_json(Obj,"stateInterval", stateInterval);
|
||||
field_to_json(Obj,"minAssociations", minAssociations);
|
||||
field_to_json(Obj,"maxAssociations", maxAssociations);
|
||||
field_to_json(Obj,"minClients", minClients);
|
||||
field_to_json(Obj,"maxClients", maxClients);
|
||||
field_to_json(Obj,"simulationLength", simulationLength);
|
||||
field_to_json(Obj,"threads", threads);
|
||||
field_to_json(Obj,"clientInterval", clientInterval);
|
||||
field_to_json(Obj,"keepAlive", keepAlive);
|
||||
field_to_json(Obj,"reconnectInterval", reconnectInterval);
|
||||
field_to_json(Obj,"concurrentDevices", concurrentDevices);
|
||||
}
|
||||
|
||||
bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"gateway", gateway);
|
||||
field_from_json(Obj,"certificate", certificate);
|
||||
field_from_json(Obj,"key", key);
|
||||
field_from_json(Obj,"macPrefix", macPrefix);
|
||||
field_from_json(Obj,"deviceType", deviceType);
|
||||
field_from_json(Obj,"devices", devices);
|
||||
field_from_json(Obj,"healthCheckInterval", healthCheckInterval);
|
||||
field_from_json(Obj,"stateInterval", stateInterval);
|
||||
field_from_json(Obj,"minAssociations", minAssociations);
|
||||
field_from_json(Obj,"maxAssociations", maxAssociations);
|
||||
field_from_json(Obj,"minClients", minClients);
|
||||
field_from_json(Obj,"maxClients", maxClients);
|
||||
field_from_json(Obj,"simulationLength", simulationLength);
|
||||
field_from_json(Obj,"threads", threads);
|
||||
field_from_json(Obj,"clientInterval", clientInterval);
|
||||
field_from_json(Obj,"keepAlive", keepAlive);
|
||||
field_from_json(Obj,"reconnectInterval", reconnectInterval);
|
||||
field_from_json(Obj,"concurrentDevices", concurrentDevices);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"list", list);
|
||||
}
|
||||
|
||||
bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"list", list);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"simulationId", simulationId);
|
||||
field_to_json(Obj,"state", state);
|
||||
field_to_json(Obj,"tx", tx);
|
||||
field_to_json(Obj,"rx", rx);
|
||||
field_to_json(Obj,"msgsTx", msgsTx);
|
||||
field_to_json(Obj,"msgsRx", msgsRx);
|
||||
field_to_json(Obj,"liveDevices", liveDevices);
|
||||
field_to_json(Obj,"timeToFullDevices", timeToFullDevices);
|
||||
field_to_json(Obj,"startTime", startTime);
|
||||
field_to_json(Obj,"endTime", endTime);
|
||||
field_to_json(Obj,"errorDevices", errorDevices);
|
||||
field_to_json(Obj,"owner", owner);
|
||||
}
|
||||
|
||||
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
|
||||
|
||||
}
|
||||
|
||||
bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dashboard::reset() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-31.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
|
||||
#define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
|
||||
|
||||
#include <vector>
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
namespace OpenWifi::OWLSObjects {
|
||||
|
||||
struct SimulationDetails {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string gateway;
|
||||
std::string certificate;
|
||||
std::string key;
|
||||
std::string macPrefix;
|
||||
std::string deviceType;
|
||||
uint64_t devices = 5;
|
||||
uint64_t healthCheckInterval = 60;
|
||||
uint64_t stateInterval = 60 ;
|
||||
uint64_t minAssociations = 1;
|
||||
uint64_t maxAssociations = 3;
|
||||
uint64_t minClients = 1 ;
|
||||
uint64_t maxClients = 3;
|
||||
uint64_t simulationLength = 60 * 60;
|
||||
uint64_t threads = 16;
|
||||
uint64_t clientInterval = 1;
|
||||
uint64_t keepAlive = 300;
|
||||
uint64_t reconnectInterval = 30 ;
|
||||
uint64_t concurrentDevices = 5;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SimulationDetailsList {
|
||||
std::vector<SimulationDetails> list;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SimulationStatus {
|
||||
std::string id;
|
||||
std::string simulationId;
|
||||
std::string state;
|
||||
uint64_t tx;
|
||||
uint64_t rx;
|
||||
uint64_t msgsTx;
|
||||
uint64_t msgsRx;
|
||||
uint64_t liveDevices;
|
||||
uint64_t timeToFullDevices;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint64_t errorDevices;
|
||||
std::string owner;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
|
||||
struct Dashboard {
|
||||
int O;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void reset();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
|
||||
@@ -251,8 +251,7 @@ namespace OpenWifi {
|
||||
VERIFY_EMAIL,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_VERIFY_EMAIL,
|
||||
SUB_SIGNUP,
|
||||
EMAIL_INVITATION
|
||||
SUB_SIGNUP
|
||||
};
|
||||
|
||||
struct ActionLink {
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
// Created by stephane bourque on 2021-10-09.
|
||||
//
|
||||
|
||||
#include <aws/sns/SNSClient.h>
|
||||
#include <aws/sns/model/PublishRequest.h>
|
||||
#include <aws/sns/model/PublishResult.h>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <aws/sns/model/GetSMSAttributesRequest.h>
|
||||
|
||||
#include "MFAServer.h"
|
||||
#include "SMS_provider_aws.h"
|
||||
#include "SMS_provider_twilio.h"
|
||||
#include "SMSSender.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -83,7 +85,7 @@ namespace OpenWifi {
|
||||
|
||||
bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) {
|
||||
if(!Enabled_) {
|
||||
poco_information(Logger(),"SMS has not been enabled. Messages cannot be sent.");
|
||||
Logger().information("SMS has not been enabled. Messages cannot be sent.");
|
||||
return false;
|
||||
}
|
||||
return ProviderImpl_->Send(PhoneNumber,Message);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace OpenWifi {
|
||||
Region_ = MicroService::instance().ConfigGetString("smssender.aws.region","");
|
||||
|
||||
if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) {
|
||||
poco_debug(Logger(),"SMSSender is disabled. Please provide key, secret, and region.");
|
||||
Logger().debug("SMSSender is disabled. Please provide key, secret, and region.");
|
||||
return false;
|
||||
}
|
||||
Running_=true;
|
||||
@@ -51,16 +51,16 @@ namespace OpenWifi {
|
||||
|
||||
auto psms_out = sns.Publish(psms_req);
|
||||
if (psms_out.IsSuccess()) {
|
||||
poco_debug(Logger(),fmt::format("SMS sent to {}",PhoneNumber));
|
||||
Logger().debug(fmt::format("SMS sent to {}",PhoneNumber));
|
||||
return true;
|
||||
}
|
||||
std::string ErrMsg{psms_out.GetError().GetMessage()};
|
||||
poco_debug(Logger(),fmt::format("SMS NOT sent to {}: {}",PhoneNumber, ErrMsg));
|
||||
Logger().debug(fmt::format("SMS NOT sent to {}: {}",PhoneNumber, ErrMsg));
|
||||
return false;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
poco_debug(Logger(),fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber));
|
||||
Logger().debug(fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
|
||||
#include "SMS_provider_twilio.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPBasicCredentials.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
bool SMS_provider_twilio::Initialize() {
|
||||
@@ -19,7 +18,7 @@ namespace OpenWifi {
|
||||
PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber","");
|
||||
|
||||
if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) {
|
||||
poco_debug(Logger(),"SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
|
||||
Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
|
||||
return false;
|
||||
}
|
||||
Running_=true;
|
||||
@@ -65,12 +64,12 @@ namespace OpenWifi {
|
||||
std::istream& rs = session.receiveResponse(res);
|
||||
|
||||
if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
poco_information(Logger(),fmt::format("Message sent to {}", PhoneNumber));
|
||||
Logger().information(fmt::format("Message sent to {}", PhoneNumber));
|
||||
return true;
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
Poco::StreamCopier::copyStream(rs,os);
|
||||
poco_information(Logger(),fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str()));
|
||||
Logger().information(fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by stephane bourque on 2021-06-17.
|
||||
//
|
||||
#include <iostream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "Poco/Net/MailMessage.h"
|
||||
#include "Poco/Net/MailRecipient.h"
|
||||
@@ -13,9 +12,9 @@
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
|
||||
#include "SMTPMailerService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "AuthService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -32,9 +31,7 @@ namespace OpenWifi {
|
||||
TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir());
|
||||
MailRetry_ = MicroService::instance().ConfigGetInt("mailer.retry",2*60);
|
||||
MailAbandon_ = MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60);
|
||||
UseHTML_ = MicroService::instance().ConfigGetBool("mailer.html",false);
|
||||
Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
|
||||
EmailLogo_ = TemplateDir_ + "/" + MicroService::instance().ConfigGetString("mailer.logo","logo.jpg");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +49,7 @@ namespace OpenWifi {
|
||||
|
||||
void SMTPMailerService::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Logger().information("Reinitializing.");
|
||||
LoadMyConfig();
|
||||
}
|
||||
|
||||
@@ -61,7 +58,7 @@ namespace OpenWifi {
|
||||
PendingMessages_.push_back(MessageEvent{.Posted= OpenWifi::Now(),
|
||||
.LastTry=0,
|
||||
.Sent=0,
|
||||
.TemplateName=Name,
|
||||
.File=Poco::File(TemplateDir_ + "/" +Name),
|
||||
.Attrs=Attrs});
|
||||
return true;
|
||||
}
|
||||
@@ -86,23 +83,15 @@ namespace OpenWifi {
|
||||
auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second;
|
||||
uint64_t now = OpenWifi::Now();
|
||||
if((i->LastTry==0 || (now-i->LastTry)>MailRetry_)) {
|
||||
switch(SendIt(*i)) {
|
||||
case MessageSendStatus::msg_sent: {
|
||||
poco_information(Logger(),fmt::format("Attempting to deliver for mail '{}'.", Recipient));
|
||||
i = Messages_.erase(i);
|
||||
} break;
|
||||
case MessageSendStatus::msg_not_sent_but_resend: {
|
||||
poco_information(Logger(),fmt::format("Mail for '{}' was not. We will retry later.", Recipient));
|
||||
i->LastTry = now;
|
||||
++i;
|
||||
} break;
|
||||
case MessageSendStatus::msg_not_sent_but_do_not_resend: {
|
||||
poco_information(Logger(),fmt::format("Mail for '{}' will not be sent. Check email address", Recipient));
|
||||
i = Messages_.erase(i);
|
||||
} break;
|
||||
if (SendIt(*i)) {
|
||||
Logger().information(fmt::format("Attempting to deliver for mail '{}'.", Recipient));
|
||||
i = Messages_.erase(i);
|
||||
} else {
|
||||
i->LastTry = now;
|
||||
++i;
|
||||
}
|
||||
} else if ((now-i->Posted)>MailAbandon_) {
|
||||
poco_information(Logger(),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));
|
||||
i = Messages_.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
@@ -117,12 +106,14 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
MessageSendStatus SMTPMailerService::SendIt(const MessageEvent &Msg) {
|
||||
|
||||
bool SMTPMailerService::SendIt(const MessageEvent &Msg) {
|
||||
std::string Recipient;
|
||||
|
||||
try
|
||||
{
|
||||
Poco::Net::MailMessage Message;
|
||||
Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
|
||||
|
||||
auto H1 = Msg.Attrs.find(SENDER);
|
||||
std::string TheSender;
|
||||
if(H1!=Msg.Attrs.end()) {
|
||||
@@ -130,40 +121,34 @@ namespace OpenWifi {
|
||||
} else {
|
||||
TheSender = Sender_ ;
|
||||
}
|
||||
|
||||
auto Message = std::make_unique<Poco::Net::MailMessage>();
|
||||
|
||||
Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
|
||||
Message->setSender( TheSender );
|
||||
Message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient));
|
||||
Message->setSubject(Msg.Attrs.find(SUBJECT)->second);
|
||||
|
||||
poco_information(Logger(),fmt::format("Sending message to:{} from {}",Recipient,TheSender));
|
||||
Message.setSender( 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()) {
|
||||
std::string Content = Msg.Attrs.find(TEXT)->second;
|
||||
Message->addContent(new Poco::Net::StringPartSource(Content));
|
||||
Message.addContent(new Poco::Net::StringPartSource(Content));
|
||||
} else {
|
||||
for(const auto &format:{"html","txt"}) {
|
||||
std::string Content = Utils::LoadFile(TemplateDir_ + Msg.TemplateName + "." + format );
|
||||
Types::StringPairVec Variables;
|
||||
FillVariables(Msg.Attrs, Variables);
|
||||
Utils::ReplaceVariables(Content, Variables);
|
||||
Message->addContent(
|
||||
new Poco::Net::StringPartSource(Content, (strcmp(format,"html") == 0 ? "text/html" : "text/plain") ));
|
||||
}
|
||||
std::string Content = Utils::LoadFile(Msg.File);
|
||||
// std::cout << "Mailing " << Content << std::endl;
|
||||
Types::StringPairVec Variables;
|
||||
FillVariables(Msg.Attrs, Variables);
|
||||
Utils::ReplaceVariables(Content, Variables);
|
||||
// std::cout << "Mailing " << Content << std::endl;
|
||||
Message.addContent(new Poco::Net::StringPartSource(Content));
|
||||
}
|
||||
|
||||
auto Logo = Msg.Attrs.find(LOGO);
|
||||
if(Logo!=Msg.Attrs.end()) {
|
||||
try {
|
||||
Poco::File LogoFile(EmailLogo_);
|
||||
Poco::File LogoFile(AuthService::GetLogoAssetFileName());
|
||||
std::ifstream IF(LogoFile.path());
|
||||
std::ostringstream OS;
|
||||
Poco::StreamCopier::copyStream(IF, OS);
|
||||
Message->addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png"));
|
||||
Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png"));
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName()));
|
||||
Logger().warning(fmt::format("Cannot add '{}' logo in email",AuthService::GetLogoAssetFileName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,23 +169,18 @@ namespace OpenWifi {
|
||||
SenderLoginUserName_,
|
||||
SenderLoginPassword_
|
||||
);
|
||||
session.sendMessage(*Message);
|
||||
session.sendMessage(Message);
|
||||
session.close();
|
||||
return MessageSendStatus::msg_sent;
|
||||
}
|
||||
catch (const Poco::Net::SMTPException &S) {
|
||||
Logger().log(S);
|
||||
return MessageSendStatus::msg_not_sent_but_do_not_resend;
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception& E)
|
||||
{
|
||||
Logger().log(E);
|
||||
return MessageSendStatus::msg_not_sent_but_resend;
|
||||
}
|
||||
catch (const std::exception &E) {
|
||||
poco_warning(Logger(),fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what()));
|
||||
return MessageSendStatus::msg_not_sent_but_do_not_resend;
|
||||
Logger().warning(fmt::format("Cannot send message to:{}, error: {}",Recipient, E.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@ namespace OpenWifi {
|
||||
LOGO,
|
||||
TEXT,
|
||||
CHALLENGE_CODE,
|
||||
SENDER,
|
||||
ACTION_LINK_HTML
|
||||
SENDER
|
||||
};
|
||||
|
||||
static const std::map<MESSAGE_ATTRIBUTES,const std::string>
|
||||
@@ -45,8 +44,7 @@ namespace OpenWifi {
|
||||
{ LOGO, "LOGO"},
|
||||
{ TEXT, "TEXT"},
|
||||
{ CHALLENGE_CODE, "CHALLENGE_CODE"},
|
||||
{ SENDER, "SENDER"},
|
||||
{ ACTION_LINK_HTML, "ACTION_LINK_HTML"},
|
||||
{ SENDER, "SENDER"}
|
||||
};
|
||||
|
||||
inline const std::string & MessageAttributeToVar(MESSAGE_ATTRIBUTES Attr) {
|
||||
@@ -58,12 +56,6 @@ namespace OpenWifi {
|
||||
}
|
||||
typedef std::map<MESSAGE_ATTRIBUTES, std::string> MessageAttributes;
|
||||
|
||||
enum class MessageSendStatus {
|
||||
msg_sent,
|
||||
msg_not_sent_but_resend,
|
||||
msg_not_sent_but_do_not_resend
|
||||
};
|
||||
|
||||
class SMTPMailerService : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
static SMTPMailerService *instance() {
|
||||
@@ -75,7 +67,7 @@ namespace OpenWifi {
|
||||
uint64_t Posted=0;
|
||||
uint64_t LastTry=0;
|
||||
uint64_t Sent=0;
|
||||
std::string TemplateName;
|
||||
Poco::File File;
|
||||
MessageAttributes Attrs;
|
||||
};
|
||||
|
||||
@@ -84,7 +76,7 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
|
||||
bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs);
|
||||
MessageSendStatus SendIt(const MessageEvent &Msg);
|
||||
bool SendIt(const MessageEvent &Msg);
|
||||
void LoadMyConfig();
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
bool Enabled() const { return Enabled_; }
|
||||
@@ -104,8 +96,6 @@ namespace OpenWifi {
|
||||
Poco::Thread SenderThr_;
|
||||
std::atomic_bool Running_=false;
|
||||
bool Enabled_=false;
|
||||
bool UseHTML_=false;
|
||||
std::string EmailLogo_{"logo.jpg"};
|
||||
|
||||
SMTPMailerService() noexcept:
|
||||
SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer")
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace OpenWifi {
|
||||
|
||||
int StorageService::Start() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
poco_information(Logger(),"Starting...");
|
||||
|
||||
StorageClass::Start();
|
||||
|
||||
@@ -52,20 +51,19 @@ namespace OpenWifi {
|
||||
Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer);
|
||||
Timer_.setStartInterval( 5 * 60 * 1000); // first run in 5 minutes
|
||||
Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours
|
||||
Timer_.start(*Archivercallback_, MicroService::instance().TimerPool());
|
||||
Timer_.start(*Archivercallback_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StorageService::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Logger().notice("Stopping.");
|
||||
Timer_.stop();
|
||||
StorageClass::Stop();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("strg-arch");
|
||||
Utils::SetThreadName("archiver");
|
||||
Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER");
|
||||
logger.information("Squiggy the DB: removing old tokens.");
|
||||
StorageService()->SubTokenDB().CleanExpiredTokens();
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#define OWSEC_TOTPCACHE_H
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "seclibs/cpptotp/bytes.h"
|
||||
#include "seclibs/qrcode/qrcodegen.hpp"
|
||||
#include "seclibs/cpptotp/otp.h"
|
||||
|
||||
@@ -44,7 +44,7 @@ static json DefaultUCentralSchema = R"(
|
||||
"switch": {
|
||||
"$ref": "#/$defs/switch"
|
||||
},
|
||||
"radiosgrep": {
|
||||
"radios": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/radio"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,169 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-09-29.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/JSON/Template.h"
|
||||
#include "Poco/Thread.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MicroServiceErrorHandler : public Poco::ErrorHandler {
|
||||
public:
|
||||
explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) {
|
||||
}
|
||||
|
||||
inline void exception(const Poco::Exception & Base) override {
|
||||
try {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
|
||||
App_.logger().log(Base);
|
||||
Base.rethrow();
|
||||
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::InvalidSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLContextException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::InvalidAddressException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::IOException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::RuntimeException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONTemplateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::ApplicationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (...) {
|
||||
poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id));
|
||||
}
|
||||
}
|
||||
|
||||
inline void exception(const std::exception & E) override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}",
|
||||
t_name,E.what(),
|
||||
t_id));
|
||||
}
|
||||
|
||||
inline void exception() override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}",
|
||||
t_name, t_id));
|
||||
}
|
||||
private:
|
||||
Poco::Util::Application &App_;
|
||||
std::string t_name;
|
||||
int t_id=0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ namespace OpenWifi {
|
||||
int Start() override {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
Logger().setLevel(Poco::Message::PRIO_INFORMATION);
|
||||
Logger().notice("Starting.");
|
||||
std::string DBType = MicroService::instance().ConfigGetString("storage.type");
|
||||
|
||||
|
||||
@@ -146,10 +146,6 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
@@ -193,58 +189,5 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationUpgradeList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
skipped,
|
||||
no_firmware,
|
||||
not_connected;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||
|
||||
inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||
N.type = "venue_upgrader";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -196,8 +196,6 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."};
|
||||
static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."};
|
||||
|
||||
static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"};
|
||||
static const struct msg DeviceIsAlreadyBusy{1145,"Device is already executing a command. Please try later."};
|
||||
}
|
||||
|
||||
|
||||
@@ -430,7 +428,6 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *RADIUSDATA = "data";
|
||||
static const char *RADIUSACCT = "acct";
|
||||
static const char *RADIUSAUTH = "auth";
|
||||
static const char *RADIUSCOA = "coa";
|
||||
static const char *RADIUSDST = "dst";
|
||||
static const char *IES = "ies";
|
||||
}
|
||||
@@ -447,7 +444,6 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
static const char *RECOVERY = "recovery";
|
||||
static const char *TELEMETRY = "telemetry";
|
||||
static const char *DEVICEUPDATE = "deviceupdate";
|
||||
static const char *VENUE_BROADCAST = "venue_broadcast";
|
||||
|
||||
enum EVENT_MSG {
|
||||
ET_UNKNOWN,
|
||||
@@ -460,8 +456,7 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_CFGPENDING,
|
||||
ET_RECOVERY,
|
||||
ET_DEVICEUPDATE,
|
||||
ET_TELEMETRY,
|
||||
ET_VENUEBROADCAST
|
||||
ET_TELEMETRY
|
||||
};
|
||||
|
||||
inline EVENT_MSG EventFromString(const std::string & Method) {
|
||||
@@ -485,8 +480,6 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
return ET_RECOVERY;
|
||||
else if(strcmp(TELEMETRY,Method.c_str())==0)
|
||||
return ET_TELEMETRY;
|
||||
else if(strcmp(VENUE_BROADCAST,Method.c_str())==0)
|
||||
return ET_VENUEBROADCAST;
|
||||
return ET_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
static std::string MakeSessionId(const std::string & token) {
|
||||
return Utils::ComputeHash(token);
|
||||
return MicroService::instance().CreateHash(token);
|
||||
}
|
||||
|
||||
void LoginDB::AddLogin( const std::string & userId, const std::string & email, const std::string &token) {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>eMail Invitation</title>
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +0,0 @@
|
||||
Dear ${RECIPIENT_EMAIL},
|
||||
|
||||
You have been invited to join the OpenWifi system. Please click below and follow the instructions
|
||||
|
||||
${ACTION_LINK}
|
||||
|
||||
Thank you!
|
||||
@@ -2,10 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>eMail Verification</title>
|
||||
|
||||
|
||||
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -2,16 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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>
|
||||
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -1,441 +0,0 @@
|
||||
<!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>
|
||||
@@ -179,19 +179,13 @@ getlogo() {
|
||||
}
|
||||
|
||||
createuser() {
|
||||
case $3 in
|
||||
root|admin|subscriber|csr|system|installer|noc|accounting)
|
||||
payload="{ \"id\": \"0\", \"email\" : \"$1\", \"currentPassword\" : \"$2\", \"changePassword\" : true, \"userRole\" : \"$3\" }"
|
||||
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/user/0" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file} ;;
|
||||
*)
|
||||
echo "Error: userRole has to be one of root|admin|subscriber|csr|system|installer|noc|accounting"
|
||||
exit 1 ;;
|
||||
esac
|
||||
payload="{ \"id\": \"0\", \"email\" : \"$1\", \"currentPassword\" : \"$2\", \"changePassword\" : true}"
|
||||
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/user/0" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
createsub() {
|
||||
@@ -205,19 +199,13 @@ createsub() {
|
||||
}
|
||||
|
||||
createuser_v() {
|
||||
case $3 in
|
||||
root|admin|subscriber|csr|system|installer|noc|accounting)
|
||||
payload="{ \"id\": \"0\", \"email\" : \"$1\", \"currentPassword\" : \"$2\", \"changePassword\" : true, \"userRole\" : \"$3\" }"
|
||||
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/user/0?email_verification=true" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file} ;;
|
||||
*)
|
||||
echo "Error: userRole has to be one of root|admin|subscriber|csr|system|installer|noc|accounting"
|
||||
exit 1 ;;
|
||||
esac
|
||||
payload="{ \"id\": \"0\", \"email\" : \"$1\", \"currentPassword\" : \"$2\", \"changePassword\" : true}"
|
||||
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/user/0?email_verification=true" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deleteuser() {
|
||||
@@ -459,7 +447,7 @@ test_service() {
|
||||
echo "----------------"
|
||||
echo "Create test user"
|
||||
echo "----------------"
|
||||
createuser testuser@mail.telecominfraproject.com 'Test123!' accounting
|
||||
createuser testuser@mail.telecominfraproject.com 'Test123!'
|
||||
check_response $result_file
|
||||
USER_ID="$(jq -r '.id' < $result_file)"
|
||||
|
||||
@@ -493,35 +481,35 @@ help() {
|
||||
echo
|
||||
echo "Usage: cli <cmd> [args]"
|
||||
echo
|
||||
echo "listendpoints Get all the system endpoints."
|
||||
echo "emailtest Generate a forgot Password e-amil to the logged in user."
|
||||
echo "me Show information about the logged user."
|
||||
echo "createuser <email> <password> <userrole> Create a user with an initial password and force the user to change password."
|
||||
echo "createuser_v <email> <password> <userrole> Same as create user but also force an e-mail verification."
|
||||
echo "deleteuser <user UUID> Delete the user."
|
||||
echo "getuser <user UUID> Get the user information."
|
||||
echo "listusers List users."
|
||||
echo "policies List the login and access policies."
|
||||
echo "setavatar <user UUID> <filename> Sets the avatar for user to the image in filename."
|
||||
echo "getavatar <user UUID> Get the avatar for the user."
|
||||
echo "deleteavatar <user UUID> Remove the avatar for a user."
|
||||
echo "sendemail <recipient> <from> Sends a test email to see if the e-mail system is working."
|
||||
echo "setloglevel <subsystem> <loglevel> Set the log level for s specific subsystem."
|
||||
echo "getloglevels Get the current log levels for all subsystems."
|
||||
echo "getloglevelnames Get the log level names available."
|
||||
echo "getsubsystemnames Get the list of subsystems."
|
||||
echo "systeminfo Get basic system information."
|
||||
echo "reloadsubsystem <subsystem name> Reload the configuration for a subsystem."
|
||||
echo "test_service Run a set of CLI commands for testing purposes"
|
||||
echo "listendpoints Get all the system endpoints."
|
||||
echo "emailtest Generate a forgot Password e-amil to the logged in user."
|
||||
echo "me Show information about the logged user."
|
||||
echo "createuser <email> <password> Create a user with an initial password and force the user to change password."
|
||||
echo "createuser_v <email> <password> Same as create user but also force an e-mail verification."
|
||||
echo "deleteuser <user UUID> Delete the user."
|
||||
echo "getuser <user UUID> Get the user information."
|
||||
echo "listusers List users."
|
||||
echo "policies List the login and access policies."
|
||||
echo "setavatar <user UUID> <filename> Sets the avatar for user to the image in filename."
|
||||
echo "getavatar <user UUID> Get the avatar for the user."
|
||||
echo "deleteavatar <user UUID> Remove the avatar for a user."
|
||||
echo "sendemail <recipient> <from> Sends a test email to see if the e-mail system is working."
|
||||
echo "setloglevel <subsystem> <loglevel> Set the log level for s specific subsystem."
|
||||
echo "getloglevels Get the current log levels for all subsystems."
|
||||
echo "getloglevelnames Get the log level names available."
|
||||
echo "getsubsystemnames Get the list of subsystems."
|
||||
echo "systeminfo Get basic system information."
|
||||
echo "reloadsubsystem <subsystem name> Reload the configuration for a subsystem."
|
||||
echo "test_service Run a set of CLI commands for testing purposes"
|
||||
echo
|
||||
}
|
||||
|
||||
shopt -s nocasematch
|
||||
|
||||
case "$1" in
|
||||
"createuser") login; createuser "$2" "$3" "$4"; logout;;
|
||||
"createuser") login; createuser "$2" "$3"; logout;;
|
||||
"createsub") login; createsub "$2" "$3"; logout;;
|
||||
"createuser_v") login; createuser_v "$2" "$3" "$4"; logout;;
|
||||
"createuser_v") login; createuser_v "$2" "$3"; logout;;
|
||||
"createsub_v") login; createsub_v "$2" "$3"; logout;;
|
||||
"deleteuser") login; deleteuser "$2" ; logout;;
|
||||
"deletesub") login; deletesub "$2" ; logout;;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
# wait-for-postgres.sh
|
||||
|
||||
set -e
|
||||
@@ -20,7 +20,7 @@ if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$RUN_CHOWN" = 'true' ]; then
|
||||
chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
|
||||
fi
|
||||
exec gosu "$OWSEC_USER" "$@"
|
||||
exec su-exec "$OWSEC_USER" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.8 KiB |
@@ -101,7 +101,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<body>
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<body>
|
||||
<div class="logo-grid">
|
||||
<div></div>
|
||||
<div><img src="/wwwassets/sub_logo.png" alt="OpenWifi"></div>
|
||||
<div><img src="/wwwassets/the_logo.png" alt="OpenWifi"></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 202 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.8 KiB |
Reference in New Issue
Block a user