Merge branch 'dev' into qt_migration
This commit is contained in:
commit
442e7eb015
127 changed files with 5657 additions and 1619 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -66,6 +66,12 @@ client/3rd/ShadowSocks/build/
|
|||
# QtCtreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# Linux files
|
||||
*.7z
|
||||
deploy/AppDir
|
||||
deploy/Tools
|
||||
deploy/AmneziaVPN*Installer*
|
||||
|
||||
# MACOS files
|
||||
.DS_Store
|
||||
client/.DS_Store
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
build-windows:
|
||||
stage: build
|
||||
tags:
|
||||
- windows
|
||||
script:
|
||||
- cmd.exe /k "deploy\windows-env.bat && cd deploy && windows.bat"
|
||||
artifacts:
|
||||
name: artifacts-windows
|
||||
paths:
|
||||
- AmneziaVPN.exe
|
||||
|
||||
build-macos:
|
||||
stage: build
|
||||
tags:
|
||||
- macos
|
||||
script:
|
||||
- cd deploy && ./macos.sh
|
||||
artifacts:
|
||||
name: artifacts-macos
|
||||
paths:
|
||||
- AmneziaVPN.dmg
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -16,12 +16,12 @@
|
|||
[submodule "client/3rd/outline-go-tun2socks"]
|
||||
path = client/3rd/outline-go-tun2socks
|
||||
url = https://github.com/Jigsaw-Code/outline-go-tun2socks.git
|
||||
[submodule "client/3rd/qzxing"]
|
||||
path = client/3rd/qzxing
|
||||
url = https://github.com/ftylitak/qzxing.git
|
||||
[submodule "client/3rd/CocoaAsyncSocket"]
|
||||
path = client/3rd/CocoaAsyncSocket
|
||||
url = https://github.com/robbiehanson/CocoaAsyncSocket.git
|
||||
[submodule "client/3rd/CocoaLumberjack"]
|
||||
path = client/3rd/CocoaLumberjack
|
||||
url = https://github.com/CocoaLumberjack/CocoaLumberjack.git
|
||||
[submodule "client/3rd/qtkeychain"]
|
||||
path = client/3rd/qtkeychain
|
||||
url = https://github.com/frankosterfeld/qtkeychain.git
|
||||
|
|
104
.travis.yml
104
.travis.yml
|
@ -23,10 +23,10 @@ jobs:
|
|||
if [ ! -f $QT_BIN_DIR/qmake ]; then \
|
||||
brew install p7zip ccache && \
|
||||
python3 -m pip install --upgrade pip && \
|
||||
pip install -U aqtinstall requests py7zr && \
|
||||
pip show aqtinstall && \
|
||||
aqt install-qt mac desktop $QT_VERSION clang_64 -m all -O $HOME/Qt && \
|
||||
aqt install-tool mac desktop tools_ifw -O $HOME/Qt ; \
|
||||
python3 -m pip install -U aqtinstall requests py7zr && \
|
||||
python3 -m pip show aqtinstall && \
|
||||
python3 -m aqt install-qt mac desktop $QT_VERSION clang_64 -m all -O $HOME/Qt && \
|
||||
python3 -m aqt install-tool mac desktop tools_ifw -O $HOME/Qt ; \
|
||||
fi
|
||||
|
||||
script:
|
||||
|
@ -77,6 +77,7 @@ jobs:
|
|||
aqt install-qt windows desktop $QT_VERSION win64_msvc2019_64 -m all -O /C/Qt && \
|
||||
aqt install-tool windows desktop tools_ifw -O /C/Qt ; \
|
||||
fi
|
||||
- choco install ccache
|
||||
|
||||
script:
|
||||
- echo set BUILD_ARCH=$BUILD_ARCH > winbuild.bat
|
||||
|
@ -87,6 +88,9 @@ jobs:
|
|||
- echo call deploy\\build_windows.bat >> winbuild.bat
|
||||
- cmd //c winbuild.bat
|
||||
|
||||
after_script:
|
||||
- ccache --show-stats
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: $GH_TOKEN
|
||||
|
@ -128,6 +132,7 @@ jobs:
|
|||
aqt install-qt windows desktop $QT_VERSION win32_msvc2019 -m all -O /C/Qt && \
|
||||
aqt install-tool windows desktop tools_ifw -O /C/Qt ; \
|
||||
fi
|
||||
- choco install ccache
|
||||
|
||||
script:
|
||||
- echo set BUILD_ARCH=$BUILD_ARCH > winbuild.bat
|
||||
|
@ -138,6 +143,9 @@ jobs:
|
|||
- echo call deploy\\build_windows.bat >> winbuild.bat
|
||||
- cmd //c winbuild.bat
|
||||
|
||||
after_script:
|
||||
- ccache --show-stats
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: $GH_TOKEN
|
||||
|
@ -156,17 +164,21 @@ jobs:
|
|||
# ------------------------------------------------------
|
||||
- name: Linux
|
||||
os: linux
|
||||
language: cpp
|
||||
dist: focal
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- p7zip
|
||||
- p7zip-full
|
||||
- python3
|
||||
- python3-pip
|
||||
- libgl-dev
|
||||
- mesa-common-dev
|
||||
- libpulse-dev
|
||||
- libxcb-*
|
||||
- libxkbcommon-x11-0
|
||||
|
||||
env:
|
||||
- QT_VERSION=5.15.2
|
||||
|
@ -205,12 +217,30 @@ jobs:
|
|||
- ccache
|
||||
- directories:
|
||||
- $HOME/Qt
|
||||
- $HOME/.ccache
|
||||
|
||||
# ------------------------------------------------------
|
||||
- name: Android
|
||||
os: linux
|
||||
language: android
|
||||
dist: xenial
|
||||
language: cpp
|
||||
dist: focal
|
||||
env:
|
||||
- QT_VERSION=5.15.2
|
||||
- QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin
|
||||
- ANDROID_API_VERSION=android-21
|
||||
- ANDROID_HOME=$HOME/sdk
|
||||
- ANDROID_SDK_ROOT=$ANDROID_HOME
|
||||
- LOCAL_ANDROID_HOME=$ANDROID_HOME
|
||||
- LOCAL_ANDROID_SDK_ROOT=$ANDROID_HOME
|
||||
- NDK_VERSION=21d
|
||||
- ANDROID_NDK_PLATFORM=android-21
|
||||
- ANDROID_NDK_HOME=$HOME/android-ndk-r${NDK_VERSION}
|
||||
- ANDROID_NDK_ROOT=$ANDROID_NDK_HOME
|
||||
- ANDROID_NDK_HOST=linux-x86_64
|
||||
- LOCAL_ANDROID_NDK_HOME=$ANDROID_NDK_HOME
|
||||
- LOCAL_ANDROID_NDK_HOST_PLATFORM=$ANDROID_NDK_HOST
|
||||
- JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
|
||||
- TERM=dumb
|
||||
|
||||
addons:
|
||||
apt:
|
||||
|
@ -218,53 +248,30 @@ jobs:
|
|||
- p7zip
|
||||
- python3
|
||||
- python3-pip
|
||||
|
||||
android:
|
||||
components:
|
||||
# Uncomment the lines below if you want to
|
||||
# use the latest revision of Android SDK Tools
|
||||
# - tools
|
||||
# - platform-tools
|
||||
|
||||
# The BuildTools version used by your project
|
||||
- build-tools-30.0.2
|
||||
|
||||
# The SDK version used to compile your project
|
||||
- android-30
|
||||
|
||||
# Additional components
|
||||
- extra
|
||||
- extra-google-google_play_services
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
|
||||
env:
|
||||
- QT_VERSION=5.15.2
|
||||
- QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin
|
||||
- USE_ANDROID_NDK_VERSION=21d
|
||||
- ANDROID_NDK_HOME=$HOME/NDK
|
||||
- openjdk-8-jdk
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ ! -f $QT_BIN_DIR/qmake ]; then \
|
||||
export PATH=$HOME/.local/bin:$PATH && \
|
||||
python3 -m pip install -U aqtinstall requests py7zr && \
|
||||
python3 -m pip show aqtinstall && \
|
||||
python3 -m aqt install-qt linux android $QT_VERSION android_armv7 -m all -O $HOME/Qt && \
|
||||
python3 -m aqt install-qt linux android $QT_VERSION android_arm64_v8a -m all -O $HOME/Qt && \
|
||||
python3 -m aqt install-qt linux android $QT_VERSION android_x86_64 -m all -O $HOME/Qt && \
|
||||
python3 -m aqt install-qt linux android $QT_VERSION android_x86 -m all -O $HOME/Qt ; \
|
||||
python3 -m aqt install-qt linux android $QT_VERSION -m all -O $HOME/Qt ; \
|
||||
fi
|
||||
|
||||
- |
|
||||
if [ ! -f $ANDROID_SDK_ROOT/tools/bin/sdkmanager ]; then \
|
||||
echo "Download Android SDK" && \
|
||||
wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO $HOME/sdk.zip > /dev/null && \
|
||||
unzip -q -d $ANDROID_SDK_ROOT $HOME/sdk.zip && \
|
||||
echo "Download tools" && \
|
||||
yes | $ANDROID_SDK_ROOT/tools/bin/sdkmanager --licenses > /dev/null 2>&1 && \
|
||||
$ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" > /dev/null 2>&1 || exit 1 ; \
|
||||
fi
|
||||
- |
|
||||
export TERM=dumb &&
|
||||
curl -L https://dl.google.com/android/repository/android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip -O &&
|
||||
unzip ./android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip > /dev/null &&
|
||||
rm android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip &&
|
||||
export ANDROID_NDK_HOME=`pwd`/android-ndk-r${USE_ANDROID_NDK_VERSION} &&
|
||||
export LOCAL_ANDROID_NDK_HOME="$ANDROID_NDK_HOME" &&
|
||||
export LOCAL_ANDROID_NDK_HOST_PLATFORM="linux-x86_64" &&
|
||||
export PATH=$PATH:${ANDROID_NDK_HOME} &&
|
||||
env
|
||||
if [ ! -f $ANDROID_NDK_ROOT/ndk-build ]; then \
|
||||
wget https://dl.google.com/android/repository/android-ndk-r${NDK_VERSION}-linux-x86_64.zip -qO $HOME/ndk.zip &&
|
||||
unzip -q -d $HOME $HOME/ndk.zip ; \
|
||||
fi
|
||||
|
||||
script:
|
||||
- bash deploy/build_android.sh
|
||||
|
@ -290,6 +297,7 @@ jobs:
|
|||
- $HOME/.gradle/wrapper/
|
||||
- $HOME/.android/build-cache
|
||||
- $ANDROID_NDK_HOME
|
||||
- $ANDROID_SDK_ROOT
|
||||
|
||||
# ------------------------------------------------------
|
||||
- name: iOS
|
||||
|
@ -308,9 +316,9 @@ jobs:
|
|||
if [ ! -f $QT_BIN_DIR/qmake ]; then \
|
||||
brew install p7zip ccache && \
|
||||
python3 -m pip install --upgrade pip && \
|
||||
pip install -U aqtinstall requests py7zr && \
|
||||
pip show aqtinstall && \
|
||||
aqt install-qt mac ios $QT_VERSION -m all -O $HOME/Qt ; \
|
||||
python3 -m pip install -U aqtinstall requests py7zr && \
|
||||
python3 -m pip show aqtinstall && \
|
||||
python3 -m aqt install-qt mac ios $QT_VERSION -m all -O $HOME/Qt ; \
|
||||
fi
|
||||
- brew install golang
|
||||
- go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
|
|
18
client/3rd/QSimpleCrypto/QSimpleCrypto.pri
Normal file
18
client/3rd/QSimpleCrypto/QSimpleCrypto.pri
Normal file
|
@ -0,0 +1,18 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/include/QAead.h \
|
||||
$$PWD/include/QBlockCipher.h \
|
||||
$$PWD/include/QCryptoError.h \
|
||||
$$PWD/include/QRsa.h \
|
||||
$$PWD/include/QSimpleCrypto_global.h \
|
||||
$$PWD/include/QX509.h \
|
||||
$$PWD/include/QX509Store.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/sources/QAead.cpp \
|
||||
$$PWD/sources/QBlockCipher.cpp \
|
||||
$$PWD/sources/QCryptoError.cpp \
|
||||
$$PWD/sources/QRsa.cpp \
|
||||
$$PWD/sources/QX509.cpp \
|
||||
$$PWD/sources/QX509Store.cpp
|
87
client/3rd/QSimpleCrypto/include/QAead.h
Normal file
87
client/3rd/QSimpleCrypto/include/QAead.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#ifndef QAEAD_H
|
||||
#define QAEAD_H
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "QCryptoError.h"
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QAead {
|
||||
public:
|
||||
QAead();
|
||||
|
||||
///
|
||||
/// \brief encryptAesGcm - Function encrypts data with Gcm algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm().
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm());
|
||||
|
||||
///
|
||||
/// \brief decryptAesGcm - Function decrypts data with Gcm algorithm.
|
||||
/// \param data - Data that will be decrypted
|
||||
/// \param key - AES key
|
||||
/// \param iv - Initialization vector
|
||||
/// \param tag - Authorization tag
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm()
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm());
|
||||
|
||||
///
|
||||
/// \brief encryptAesCcm - Function encrypts data with Ccm algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm().
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm());
|
||||
|
||||
///
|
||||
/// \brief decryptAesCcm - Function decrypts data with Ccm algorithm.
|
||||
/// \param data - Data that will be decrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm());
|
||||
|
||||
///
|
||||
/// \brief error - Error handler class.
|
||||
///
|
||||
QCryptoError error;
|
||||
};
|
||||
} // namespace QSimpleCrypto
|
||||
|
||||
#endif // QAEAD_H
|
84
client/3rd/QSimpleCrypto/include/QBlockCipher.h
Normal file
84
client/3rd/QSimpleCrypto/include/QBlockCipher.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#ifndef QBLOCKCIPHER_H
|
||||
#define QBLOCKCIPHER_H
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "QCryptoError.h"
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QBlockCipher {
|
||||
|
||||
#define Aes128Rounds 10
|
||||
#define Aes192Rounds 12
|
||||
#define Aes256Rounds 14
|
||||
|
||||
public:
|
||||
QBlockCipher();
|
||||
|
||||
///
|
||||
/// \brief generateRandomBytes - Function generates random bytes by size.
|
||||
/// \param size - Size of generated bytes.
|
||||
/// \return Returns random bytes.
|
||||
///
|
||||
QByteArray generateRandomBytes(const int& size);
|
||||
QByteArray generateSecureRandomBytes(const int& size);
|
||||
|
||||
///
|
||||
/// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param password - Encryption password.
|
||||
/// \param salt - Random delta.
|
||||
/// \param rounds - Transformation rounds.
|
||||
/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray encryptAesBlockCipher(QByteArray data, QByteArray key,
|
||||
QByteArray iv = "", const int& rounds = Aes256Rounds,
|
||||
const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512());
|
||||
|
||||
///
|
||||
/// \brief decryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm.
|
||||
/// \param data - Data that will be decrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param password - Decryption password.
|
||||
/// \param salt - Random delta.
|
||||
/// \param rounds - Transformation rounds.
|
||||
/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray decryptAesBlockCipher(QByteArray data, QByteArray key,
|
||||
QByteArray iv = "", const int& rounds = Aes256Rounds,
|
||||
const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512());
|
||||
|
||||
///
|
||||
/// \brief error - Error handler class.
|
||||
///
|
||||
QCryptoError error;
|
||||
};
|
||||
} // namespace QSimpleCrypto
|
||||
|
||||
#endif // QBLOCKCIPHER_H
|
45
client/3rd/QSimpleCrypto/include/QCryptoError.h
Normal file
45
client/3rd/QSimpleCrypto/include/QCryptoError.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef QCRYPTOERROR_H
|
||||
#define QCRYPTOERROR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
/// TODO: Add Special error code for each error.
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QCryptoError : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QCryptoError(QObject* parent = nullptr);
|
||||
|
||||
///
|
||||
/// \brief setError - Sets error information
|
||||
/// \param errorCode - Error code.
|
||||
/// \param errorSummary - Error summary.
|
||||
///
|
||||
inline void setError(const quint8 errorCode, const QString& errorSummary)
|
||||
{
|
||||
m_currentErrorCode = errorCode;
|
||||
m_errorSummary = errorSummary;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief lastError - Returns last error.
|
||||
/// \return Returns eror ID and error Text.
|
||||
///
|
||||
inline QPair<quint8, QString> lastError() const
|
||||
{
|
||||
return QPair<quint8, QString>(m_currentErrorCode, m_errorSummary);
|
||||
}
|
||||
|
||||
private:
|
||||
quint8 m_currentErrorCode;
|
||||
QString m_errorSummary;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QCRYPTOERROR_H
|
104
client/3rd/QSimpleCrypto/include/QRsa.h
Normal file
104
client/3rd/QSimpleCrypto/include/QRsa.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#ifndef QRSA_H
|
||||
#define QRSA_H
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "QCryptoError.h"
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QRsa {
|
||||
|
||||
#define PublicEncrypt 0
|
||||
#define PrivateEncrypt 1
|
||||
#define PublicDecrypt 2
|
||||
#define PrivateDecrypt 3
|
||||
|
||||
public:
|
||||
QRsa();
|
||||
|
||||
///
|
||||
/// \brief generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure.
|
||||
/// \param bits - RSA key size.
|
||||
/// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537.
|
||||
/// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak.
|
||||
///
|
||||
RSA* generateRsaKeys(const int& bits, const int& rsaBigNumber);
|
||||
|
||||
///
|
||||
/// \brief savePublicKey - Saves to file RSA public key.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param publicKeyFileName - Public key file name.
|
||||
///
|
||||
void savePublicKey(RSA *rsa, const QByteArray& publicKeyFileName);
|
||||
|
||||
///
|
||||
/// \brief savePrivateKey - Saves to file RSA private key.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param privateKeyFileName - Private key file name.
|
||||
/// \param password - Private key password.
|
||||
/// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
///
|
||||
void savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password = "", const EVP_CIPHER* cipher = nullptr);
|
||||
|
||||
///
|
||||
/// \brief getPublicKeyFromFile - Gets RSA public key from a file.
|
||||
/// \param filePath - File path to public key file.
|
||||
/// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak.
|
||||
///
|
||||
EVP_PKEY* getPublicKeyFromFile(const QByteArray& filePath);
|
||||
|
||||
///
|
||||
/// \brief getPrivateKeyFromFile - Gets RSA private key from a file.
|
||||
/// \param filePath - File path to private key file.
|
||||
/// \param password - Private key password.
|
||||
/// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak.
|
||||
///
|
||||
EVP_PKEY* getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password = "");
|
||||
|
||||
///
|
||||
/// \brief encrypt - Encrypt data with RSA algorithm.
|
||||
/// \param plaintext - Text that must be encrypted.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT).
|
||||
/// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc.
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray encrypt(QByteArray plainText, RSA* rsa, const int& encryptType = PublicEncrypt, const int& padding = RSA_PKCS1_PADDING);
|
||||
|
||||
///
|
||||
/// \brief decrypt - Decrypt data with RSA algorithm.
|
||||
/// \param cipherText - Text that must be decrypted.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT).
|
||||
/// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc.
|
||||
/// \return - Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType = PrivateDecrypt, const int& padding = RSA_PKCS1_PADDING);
|
||||
|
||||
///
|
||||
/// \brief error - Error handler class.
|
||||
///
|
||||
QCryptoError error;
|
||||
};
|
||||
} // namespace QSimpleCrypto
|
||||
|
||||
#endif // QRSA_H
|
9
client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h
Normal file
9
client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef QSIMPLECRYPTO_GLOBAL_H
|
||||
#define QSIMPLECRYPTO_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#define QSIMPLECRYPTO_EXPORT
|
||||
|
||||
#endif // QSIMPLECRYPTO_GLOBAL_H
|
87
client/3rd/QSimpleCrypto/include/QX509.h
Normal file
87
client/3rd/QSimpleCrypto/include/QX509.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#ifndef QX509_H
|
||||
#define QX509_H
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
#include "QCryptoError.h"
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QX509 {
|
||||
|
||||
#define oneYear 31536000L
|
||||
#define x509LastVersion 2
|
||||
|
||||
public:
|
||||
QX509();
|
||||
|
||||
///
|
||||
/// \brief loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure.
|
||||
/// \param fileName - File path to certificate.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak.
|
||||
///
|
||||
X509* loadCertificateFromFile(const QByteArray& fileName);
|
||||
|
||||
///
|
||||
/// \brief signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure.
|
||||
/// \param endCertificate - Certificate that will be signed
|
||||
/// \param caCertificate - CA certificate that will sign end certificate
|
||||
/// \param caPrivateKey - CA certificate private key
|
||||
/// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened.
|
||||
///
|
||||
X509* signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName = "");
|
||||
|
||||
///
|
||||
/// \brief verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure.
|
||||
/// \param x509 - OpenSSL X509. That certificate will be verified.
|
||||
/// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened
|
||||
///
|
||||
X509* verifyCertificate(X509* x509, X509_STORE* store);
|
||||
|
||||
///
|
||||
/// \brief generateSelfSignedCertificate - Function generatesand returns self signed X509.
|
||||
/// \param rsa - OpenSSL RSA.
|
||||
/// \param additionalData - Certificate information.
|
||||
/// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it.
|
||||
/// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512().
|
||||
/// \param serialNumber - X509 certificate serial number.
|
||||
/// \param version - X509 certificate version.
|
||||
/// \param notBefore - X509 start date.
|
||||
/// \param notAfter - X509 end date.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak.
|
||||
///
|
||||
X509* generateSelfSignedCertificate(const RSA* rsa, const QMap<QByteArray, QByteArray>& additionalData,
|
||||
const QByteArray& certificateFileName = "", const EVP_MD* md = EVP_sha512(),
|
||||
const long& serialNumber = 1, const long& version = x509LastVersion,
|
||||
const long& notBefore = 0, const long& notAfter = oneYear);
|
||||
|
||||
///
|
||||
/// \brief error - Error handler class.
|
||||
///
|
||||
QCryptoError error;
|
||||
};
|
||||
} // namespace QSimpleCrypto
|
||||
|
||||
#endif // QX509_H
|
120
client/3rd/QSimpleCrypto/include/QX509Store.h
Normal file
120
client/3rd/QSimpleCrypto/include/QX509Store.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#ifndef QX509STORE_H
|
||||
#define QX509STORE_H
|
||||
|
||||
#include "QSimpleCrypto_global.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "QCryptoError.h"
|
||||
|
||||
// clang-format off
|
||||
namespace QSimpleCrypto
|
||||
{
|
||||
class QSIMPLECRYPTO_EXPORT QX509Store {
|
||||
public:
|
||||
QX509Store();
|
||||
|
||||
///
|
||||
/// \brief addCertificateToStore
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param x509 - OpenSSL X509.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool addCertificateToStore(X509_STORE* store, X509* x509);
|
||||
|
||||
///
|
||||
/// \brief addLookup
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method);
|
||||
|
||||
///
|
||||
/// \brief setCertificateDepth
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool setDepth(X509_STORE* store, const int& depth);
|
||||
|
||||
///
|
||||
/// \brief setFlag
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool setFlag(X509_STORE* store, const unsigned long& flag);
|
||||
|
||||
///
|
||||
/// \brief setFlag
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool setPurpose(X509_STORE* store, const int& purpose);
|
||||
|
||||
///
|
||||
/// \brief setTrust
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool setTrust(X509_STORE* store, const int& trust);
|
||||
|
||||
///
|
||||
/// \brief setDefaultPaths
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool setDefaultPaths(X509_STORE* store);
|
||||
|
||||
///
|
||||
/// \brief loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param fileName - File name. Example: "caCertificate.pem".
|
||||
/// \param dirPath - Path to file. Example: "path/To/File".
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath);
|
||||
|
||||
///
|
||||
/// \brief loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param file - Qt QFile that will be loaded.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool loadLocations(X509_STORE* store, const QFile& file);
|
||||
|
||||
///
|
||||
/// \brief loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param fileInfo - Qt QFileInfo.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool loadLocations(X509_STORE* store, const QFileInfo& fileInfo);
|
||||
|
||||
///
|
||||
/// \brief error - Error handler class.
|
||||
///
|
||||
QCryptoError error;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QX509STORE_H
|
364
client/3rd/QSimpleCrypto/sources/QAead.cpp
Normal file
364
client/3rd/QSimpleCrypto/sources/QAead.cpp
Normal file
|
@ -0,0 +1,364 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#include "include/QAead.h"
|
||||
|
||||
QSimpleCrypto::QAead::QAead()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QAEAD::encryptAesGcm - Function encrypts data with Gcm algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm().
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QAead::encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (encryptionCipher == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set data length */
|
||||
int plainTextLength = data.size();
|
||||
int cipherTextLength = 0;
|
||||
|
||||
/* Initialize cipherText. Here encrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> cipherText { new unsigned char[plainTextLength]() };
|
||||
if (cipherText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'ciphertext'.");
|
||||
}
|
||||
|
||||
/* Initialize encryption operation. */
|
||||
if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast<unsigned char*>(key.data()), reinterpret_cast<unsigned char*>(iv.data()))) {
|
||||
throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
|
||||
if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) {
|
||||
throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
// /* Check if aad need to be used */
|
||||
// if (aad.length() > 0) {
|
||||
// /* Provide any AAD data. This can be called zero or more times as required */
|
||||
// if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast<unsigned char*>(aad.data()), aad.length())) {
|
||||
// throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
// }
|
||||
|
||||
/*
|
||||
* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast<const unsigned char*>(data.data()), plainTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the encryption. Normally cipher text bytes may be written at
|
||||
* this stage, but this does not occur in GCM mode
|
||||
*/
|
||||
if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) {
|
||||
throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
// /* Get tag */
|
||||
// if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_GET_TAG, tag->length(), reinterpret_cast<unsigned char*>(tag->data()))) {
|
||||
// throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray encryptedData = QByteArray(reinterpret_cast<char*>(cipherText.get()), cipherTextLength);
|
||||
|
||||
return encryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QAead::error.setError(1, exception.what());
|
||||
return QByteArray();
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QAead::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QAEAD::decryptAesGcm - Function decrypts data with Gcm algorithm.
|
||||
/// \param data - Data that will be decrypted
|
||||
/// \param key - AES key
|
||||
/// \param iv - Initialization vector
|
||||
/// \param tag - Authorization tag
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm()
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QAead::decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (decryptionCipher.get() == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set data length */
|
||||
int cipherTextLength = data.size();
|
||||
int plainTextLength = 0;
|
||||
|
||||
/* Initialize plainText. Here decrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> plainText { new unsigned char[cipherTextLength]() };
|
||||
if (plainText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'plaintext'.");
|
||||
}
|
||||
|
||||
/* Initialize decryption operation. */
|
||||
if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast<unsigned char*>(key.data()), reinterpret_cast<unsigned char*>(iv.data()))) {
|
||||
throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
|
||||
if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) {
|
||||
throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
// /* Check if aad need to be used */
|
||||
// if (aad.length() > 0) {
|
||||
// /* Provide any AAD data. This can be called zero or more times as required */
|
||||
// if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast<unsigned char*>(aad.data()), aad.length())) {
|
||||
// throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
// }
|
||||
|
||||
/*
|
||||
* Provide the message to be decrypted, and obtain the plain text output.
|
||||
* EVP_DecryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast<const unsigned char*>(data.data()), cipherTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
// /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
|
||||
// if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_TAG, tag->length(), reinterpret_cast<unsigned char*>(tag->data()))) {
|
||||
// throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
|
||||
/*
|
||||
* Finalize the decryption. A positive return value indicates success,
|
||||
* anything else is a failure - the plain text is not trustworthy.
|
||||
*/
|
||||
if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) {
|
||||
throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray decryptedData = QByteArray(reinterpret_cast<char*>(plainText.get()), plainTextLength);
|
||||
|
||||
return decryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QAead::error.setError(1, exception.what());
|
||||
return QByteArray();
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QAead::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QAEAD::encryptAesCcm - Function encrypts data with Ccm algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm().
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QAead::encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (encryptionCipher == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set data length */
|
||||
int plainTextLength = data.size();
|
||||
int cipherTextLength = 0;
|
||||
|
||||
/* Initialize cipherText. Here encrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> cipherText { new unsigned char[plainTextLength]() };
|
||||
if (cipherText.get() == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'ciphertext'.");
|
||||
}
|
||||
|
||||
/* Initialize encryption operation. */
|
||||
if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast<unsigned char*>(key.data()), reinterpret_cast<unsigned char*>(iv.data()))) {
|
||||
throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
|
||||
if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) {
|
||||
throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set tag length */
|
||||
if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), nullptr)) {
|
||||
throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Check if aad need to be used */
|
||||
if (aad.length() > 0) {
|
||||
/* Provide the total plain text length */
|
||||
if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, nullptr, plainTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide total plaintext length. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as required */
|
||||
if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast<unsigned char*>(aad.data()), aad.length())) {
|
||||
throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast<const unsigned char*>(data.data()), plainTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the encryption. Normally ciphertext bytes may be written at
|
||||
* this stage, but this does not occur in GCM mode
|
||||
*/
|
||||
if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) {
|
||||
throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Get tag */
|
||||
if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_GET_TAG, tag->length(), reinterpret_cast<unsigned char*>(tag->data()))) {
|
||||
throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray encryptedData = QByteArray(reinterpret_cast<char*>(cipherText.get()), cipherTextLength);
|
||||
|
||||
return encryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QAead::error.setError(1, exception.what());
|
||||
return QByteArray();
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QAead::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QAEAD::decryptAesCcm - Function decrypts data with Ccm algorithm.
|
||||
/// \param data - Data that will be decrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param tag - Authorization tag.
|
||||
/// \param aad - Additional authenticated data. Must be nullptr, if not used.
|
||||
/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QAead::decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (decryptionCipher.get() == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set data length */
|
||||
int cipherTextLength = data.size();
|
||||
int plainTextLength = 0;
|
||||
|
||||
/* Initialize plainText. Here decrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> plainText { new unsigned char[cipherTextLength]() };
|
||||
if (plainText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'plaintext'.");
|
||||
}
|
||||
|
||||
/* Initialize decryption operation. */
|
||||
if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast<unsigned char*>(key.data()), reinterpret_cast<unsigned char*>(iv.data()))) {
|
||||
throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
|
||||
if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) {
|
||||
throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
|
||||
if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), reinterpret_cast<unsigned char*>(tag->data()))) {
|
||||
throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Check if aad need to be used */
|
||||
if (aad.length() > 0) {
|
||||
/* Provide the total ciphertext length */
|
||||
if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, nullptr, cipherTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide total plaintext length. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as required */
|
||||
if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast<unsigned char*>(aad.data()), aad.length())) {
|
||||
throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide the message to be decrypted, and obtain the plaintext output.
|
||||
* EVP_DecryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast<const unsigned char*>(data.data()), cipherTextLength)) {
|
||||
throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the decryption. A positive return value indicates success,
|
||||
* anything else is a failure - the plaintext is not trustworthy.
|
||||
*/
|
||||
if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) {
|
||||
throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray decryptedData = QByteArray(reinterpret_cast<char*>(plainText.get()), plainTextLength);
|
||||
|
||||
return decryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QAead::error.setError(1, exception.what());
|
||||
return QByteArray();
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QAead::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
193
client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp
Normal file
193
client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#include "include/QBlockCipher.h"
|
||||
|
||||
QSimpleCrypto::QBlockCipher::QBlockCipher()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QBlockCipher::generateRandomBytes - Function generates random bytes by size.
|
||||
/// \param size - Size of generated bytes.
|
||||
/// \return Returns random bytes.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QBlockCipher::generateRandomBytes(const int& size)
|
||||
{
|
||||
unsigned char arr[sizeof(size)];
|
||||
RAND_bytes(arr, sizeof(size));
|
||||
|
||||
QByteArray buffer = QByteArray(reinterpret_cast<char*>(arr), size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QByteArray QSimpleCrypto::QBlockCipher::generateSecureRandomBytes(const int &size)
|
||||
{
|
||||
unsigned char arr[sizeof(size)];
|
||||
RAND_priv_bytes(arr, sizeof(size));
|
||||
|
||||
QByteArray buffer = QByteArray(reinterpret_cast<char*>(arr), size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
||||
/// \param data - Data that will be encrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param password - Encryption password.
|
||||
/// \param salt - Random delta.
|
||||
/// \param rounds - Transformation rounds.
|
||||
/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QBlockCipher::encryptAesBlockCipher(QByteArray data, QByteArray key,
|
||||
QByteArray iv,
|
||||
const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (encryptionCipher == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Reinterpret values for multi use */
|
||||
unsigned char* m_key = reinterpret_cast<unsigned char*>(key.data());
|
||||
unsigned char* m_iv = reinterpret_cast<unsigned char*>(iv.data());
|
||||
|
||||
/* Set data length */
|
||||
int cipherTextLength(data.size() + AES_BLOCK_SIZE);
|
||||
int finalLength = 0;
|
||||
|
||||
/* Initialize cipcherText. Here encrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> cipherText { new unsigned char[cipherTextLength]() };
|
||||
if (cipherText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'cipherText'.");
|
||||
}
|
||||
|
||||
// Bug here
|
||||
// /* Start encryption with password based encryption routine */
|
||||
// if (!EVP_BytesToKey(cipher, md, reinterpret_cast<unsigned char*>(salt.data()), reinterpret_cast<unsigned char*>(password.data()), password.length(), rounds, m_key, m_iv)) {
|
||||
// throw std::runtime_error("Couldn't start encryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
|
||||
/* Initialize encryption operation. */
|
||||
if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, m_key, m_iv)) {
|
||||
throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast<const unsigned char*>(data.data()), data.size())) {
|
||||
throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finalize the encryption. Normally ciphertext bytes may be written at this stage */
|
||||
if (!EVP_EncryptFinal(encryptionCipher.get(), cipherText.get() + cipherTextLength, &finalLength)) {
|
||||
throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray encryptedData = QByteArray(reinterpret_cast<char*>(cipherText.get()), cipherTextLength + finalLength);
|
||||
|
||||
return encryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QBlockCipher::error.setError(1, exception.what());
|
||||
return QByteArray();
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm.
|
||||
/// \param data - Data that will be decrypted.
|
||||
/// \param key - AES key.
|
||||
/// \param iv - Initialization vector.
|
||||
/// \param password - Decryption password.
|
||||
/// \param salt - Random delta.
|
||||
/// \param rounds - Transformation rounds.
|
||||
/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512().
|
||||
/// \return Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QBlockCipher::decryptAesBlockCipher(QByteArray data, QByteArray key,
|
||||
QByteArray iv,
|
||||
const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md)
|
||||
{
|
||||
try {
|
||||
/* Initialize EVP_CIPHER_CTX */
|
||||
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX*)> decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
|
||||
if (decryptionCipher == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Reinterpret values for multi use */
|
||||
unsigned char* m_key = reinterpret_cast<unsigned char*>(key.data());
|
||||
unsigned char* m_iv = reinterpret_cast<unsigned char*>(iv.data());
|
||||
|
||||
/* Set data length */
|
||||
int plainTextLength(data.size());
|
||||
int finalLength = 0;
|
||||
|
||||
/* Initialize plainText. Here decrypted data will be stored */
|
||||
std::unique_ptr<unsigned char[]> plainText { new unsigned char[plainTextLength + AES_BLOCK_SIZE]() };
|
||||
if (plainText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for \'plainText\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
// Bug here
|
||||
// /* Start encryption with password based encryption routine */
|
||||
// if (!EVP_BytesToKey(cipher, md, reinterpret_cast<const unsigned char*>(salt.data()), reinterpret_cast<const unsigned char*>(password.data()), password.length(), rounds, m_key, m_iv)) {
|
||||
// throw std::runtime_error("Couldn't start decryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
// }
|
||||
|
||||
/* Initialize decryption operation. */
|
||||
if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, m_key, m_iv)) {
|
||||
throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide the message to be decrypted, and obtain the plaintext output.
|
||||
* EVP_DecryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast<const unsigned char*>(data.data()), data.size())) {
|
||||
throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the decryption. A positive return value indicates success,
|
||||
* anything else is a failure - the plaintext is not trustworthy.
|
||||
*/
|
||||
if (!EVP_DecryptFinal(decryptionCipher.get(), plainText.get() + plainTextLength, &finalLength)) {
|
||||
throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Finilize data to be readable with qt */
|
||||
QByteArray decryptedData = QByteArray(reinterpret_cast<char*>(plainText.get()), plainTextLength + finalLength);
|
||||
|
||||
return decryptedData;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QBlockCipher::error.setError(1, exception.what());
|
||||
return QByteArray(exception.what());
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
6
client/3rd/QSimpleCrypto/sources/QCryptoError.cpp
Normal file
6
client/3rd/QSimpleCrypto/sources/QCryptoError.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "include/QCryptoError.h"
|
||||
|
||||
QSimpleCrypto::QCryptoError::QCryptoError(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
274
client/3rd/QSimpleCrypto/sources/QRsa.cpp
Normal file
274
client/3rd/QSimpleCrypto/sources/QRsa.cpp
Normal file
|
@ -0,0 +1,274 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#include "include/QRsa.h"
|
||||
|
||||
QSimpleCrypto::QRsa::QRsa()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure.
|
||||
/// \param bits - RSA key size.
|
||||
/// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537.
|
||||
/// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak.
|
||||
///
|
||||
RSA* QSimpleCrypto::QRsa::generateRsaKeys(const int& bits, const int& rsaBigNumber)
|
||||
{
|
||||
try {
|
||||
/* Initialize big number */
|
||||
std::unique_ptr<BIGNUM, void (*)(BIGNUM*)> bigNumber { BN_new(), BN_free };
|
||||
if (bigNumber == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'bigNumber\'. BN_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Set big number */
|
||||
if (!BN_set_word(bigNumber.get(), rsaBigNumber)) {
|
||||
throw std::runtime_error("Couldn't set bigNumber. BN_set_word(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize RSA */
|
||||
RSA* rsa = nullptr;
|
||||
if (!(rsa = RSA_new())) {
|
||||
throw std::runtime_error("Couldn't initialize x509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Generate key pair and store it in RSA */
|
||||
if (!RSA_generate_key_ex(rsa, bits, bigNumber.get(), nullptr)) {
|
||||
throw std::runtime_error("Couldn't generate RSA. RSA_generate_key_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
return rsa;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::savePublicKey - Saves to file RSA public key.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param publicKeyFileName - Public key file name.
|
||||
///
|
||||
void QSimpleCrypto::QRsa::savePublicKey(RSA* rsa, const QByteArray& publicKeyFileName)
|
||||
{
|
||||
try {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> bioPublicKey { BIO_new_file(publicKeyFileName.data(), "w+"), BIO_free_all };
|
||||
if (bioPublicKey == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize \'bioPublicKey\'. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write public key on file */
|
||||
if (!PEM_write_bio_RSA_PUBKEY(bioPublicKey.get(), rsa)) {
|
||||
throw std::runtime_error("Couldn't save public key. PEM_write_bio_RSAPublicKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::savePrivateKey - Saves to file RSA private key.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param privateKeyFileName - Private key file name.
|
||||
/// \param password - Private key password.
|
||||
/// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc().
|
||||
///
|
||||
void QSimpleCrypto::QRsa::savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password, const EVP_CIPHER* cipher)
|
||||
{
|
||||
try {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> bioPrivateKey { BIO_new_file(privateKeyFileName.data(), "w+"), BIO_free_all };
|
||||
if (bioPrivateKey == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write private key to file */
|
||||
if (!PEM_write_bio_RSAPrivateKey(bioPrivateKey.get(), rsa, cipher, reinterpret_cast<unsigned char*>(password.data()), password.size(), nullptr, nullptr)) {
|
||||
throw std::runtime_error("Couldn't save private key. PEM_write_bio_RSAPrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::getPublicKeyFromFile - Gets RSA public key from a file.
|
||||
/// \param filePath - File path to public key file.
|
||||
/// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak.
|
||||
///
|
||||
EVP_PKEY* QSimpleCrypto::QRsa::getPublicKeyFromFile(const QByteArray& filePath)
|
||||
{
|
||||
try {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> bioPublicKey { BIO_new_file(filePath.data(), "r"), BIO_free_all };
|
||||
if (bioPublicKey == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize bioPublicKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize EVP_PKEY */
|
||||
EVP_PKEY* keyStore = nullptr;
|
||||
if (!(keyStore = EVP_PKEY_new())) {
|
||||
throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write private key to file */
|
||||
if (!PEM_read_bio_PUBKEY(bioPublicKey.get(), &keyStore, nullptr, nullptr)) {
|
||||
throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
return keyStore;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::getPrivateKeyFromFile - Gets RSA private key from a file.
|
||||
/// \param filePath - File path to private key file.
|
||||
/// \param password - Private key password.
|
||||
/// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak.
|
||||
///
|
||||
EVP_PKEY* QSimpleCrypto::QRsa::getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password)
|
||||
{
|
||||
try {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> bioPrivateKey { BIO_new_file(filePath.data(), "r"), BIO_free_all };
|
||||
if (bioPrivateKey == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize EVP_PKEY */
|
||||
EVP_PKEY* keyStore = nullptr;
|
||||
if (!(keyStore = EVP_PKEY_new())) {
|
||||
throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write private key to file */
|
||||
if (!PEM_read_bio_PrivateKey(bioPrivateKey.get(), &keyStore, nullptr, (void*)password.data())) {
|
||||
throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
return keyStore;
|
||||
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::encrypt - Encrypt data with RSA algorithm.
|
||||
/// \param plaintext - Text that must be encrypted.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT).
|
||||
/// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc.
|
||||
/// \return Returns encrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QRsa::encrypt(QByteArray plainText, RSA* rsa, const int& encryptType, const int& padding)
|
||||
{
|
||||
try {
|
||||
/* Initialize array. Here encrypted data will be saved */
|
||||
std::unique_ptr<unsigned char[]> cipherText { new unsigned char[RSA_size(rsa)]() };
|
||||
if (cipherText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'cipherText'.");
|
||||
}
|
||||
|
||||
/* Result of encryption operation */
|
||||
short int result = 0;
|
||||
|
||||
/* Execute encryption operation */
|
||||
if (encryptType == PublicDecrypt) {
|
||||
result = RSA_public_encrypt(plainText.size(), reinterpret_cast<unsigned char*>(plainText.data()), cipherText.get(), rsa, padding);
|
||||
} else if (encryptType == PrivateDecrypt) {
|
||||
result = RSA_private_encrypt(plainText.size(), reinterpret_cast<unsigned char*>(plainText.data()), cipherText.get(), rsa, padding);
|
||||
}
|
||||
|
||||
/* Check for result */
|
||||
if (result <= -1) {
|
||||
throw std::runtime_error("Couldn't encrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Get encrypted data */
|
||||
const QByteArray& encryptedData = QByteArray(reinterpret_cast<char*>(cipherText.get()), RSA_size(rsa));
|
||||
|
||||
return encryptedData;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return "";
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QRSA::decrypt - Decrypt data with RSA algorithm.
|
||||
/// \param cipherText - Text that must be decrypted.
|
||||
/// \param rsa - OpenSSL RSA structure.
|
||||
/// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT).
|
||||
/// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc.
|
||||
/// \return - Returns decrypted data or "", if error happened.
|
||||
///
|
||||
QByteArray QSimpleCrypto::QRsa::decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType, const int& padding)
|
||||
{
|
||||
try {
|
||||
/* Initialize array. Here decrypted data will be saved */
|
||||
std::unique_ptr<unsigned char[]> plainText { new unsigned char[cipherText.size()]() };
|
||||
if (plainText == nullptr) {
|
||||
throw std::runtime_error("Couldn't allocate memory for 'plainText'.");
|
||||
}
|
||||
|
||||
/* Result of decryption operation */
|
||||
short int result = 0;
|
||||
|
||||
/* Execute decryption operation */
|
||||
if (decryptType == PublicDecrypt) {
|
||||
result = RSA_public_decrypt(RSA_size(rsa), reinterpret_cast<unsigned char*>(cipherText.data()), plainText.get(), rsa, padding);
|
||||
} else if (decryptType == PrivateDecrypt) {
|
||||
result = RSA_private_decrypt(RSA_size(rsa), reinterpret_cast<unsigned char*>(cipherText.data()), plainText.get(), rsa, padding);
|
||||
}
|
||||
|
||||
/* Check for result */
|
||||
if (result <= -1) {
|
||||
throw std::runtime_error("Couldn't decrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Get decrypted data */
|
||||
const QByteArray& decryptedData = QByteArray(reinterpret_cast<char*>(plainText.get()));
|
||||
|
||||
return decryptedData;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QRsa::error.setError(1, exception.what());
|
||||
return "";
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QRsa::error.setError(2, "Unknown error!");
|
||||
return "";
|
||||
}
|
||||
}
|
234
client/3rd/QSimpleCrypto/sources/QX509.cpp
Normal file
234
client/3rd/QSimpleCrypto/sources/QX509.cpp
Normal file
|
@ -0,0 +1,234 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#include "include/QX509.h"
|
||||
|
||||
QSimpleCrypto::QX509::QX509()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509::loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure.
|
||||
/// \param fileName - File path to certificate.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak.
|
||||
///
|
||||
X509* QSimpleCrypto::QX509::loadCertificateFromFile(const QByteArray& fileName)
|
||||
{
|
||||
try {
|
||||
/* Initialize X509 */
|
||||
X509* x509 = nullptr;
|
||||
if (!(x509 = X509_new())) {
|
||||
throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> certFile { BIO_new_file(fileName.data(), "r+"), BIO_free_all };
|
||||
if (certFile == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Read file */
|
||||
if (!PEM_read_bio_X509(certFile.get(), &x509, nullptr, nullptr)) {
|
||||
throw std::runtime_error("Couldn't read certificate file from disk. PEM_read_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
return x509;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QX509::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QX509::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509::signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure.
|
||||
/// \param endCertificate - Certificate that will be signed
|
||||
/// \param caCertificate - CA certificate that will sign end certificate
|
||||
/// \param caPrivateKey - CA certificate private key
|
||||
/// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened.
|
||||
///
|
||||
X509* QSimpleCrypto::QX509::signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName)
|
||||
{
|
||||
try {
|
||||
/* Set issuer to CA's subject. */
|
||||
if (!X509_set_issuer_name(endCertificate, X509_get_subject_name(caCertificate))) {
|
||||
throw std::runtime_error("Couldn't set issuer name for X509. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Sign the certificate with key. */
|
||||
if (!X509_sign(endCertificate, caPrivateKey, EVP_sha256())) {
|
||||
throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write certificate file on disk. If needed */
|
||||
if (!fileName.isEmpty()) {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> certFile { BIO_new_file(fileName.data(), "w+"), BIO_free_all };
|
||||
if (certFile == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write file on disk */
|
||||
if (!PEM_write_bio_X509(certFile.get(), endCertificate)) {
|
||||
throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
return endCertificate;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QX509::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QX509::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509::verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure.
|
||||
/// \param x509 - OpenSSL X509. That certificate will be verified.
|
||||
/// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened
|
||||
///
|
||||
X509* QSimpleCrypto::QX509::verifyCertificate(X509* x509, X509_STORE* store)
|
||||
{
|
||||
try {
|
||||
/* Initialize X509_STORE_CTX */
|
||||
std::unique_ptr<X509_STORE_CTX, void (*)(X509_STORE_CTX*)> ctx { X509_STORE_CTX_new(), X509_STORE_CTX_free };
|
||||
if (ctx == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set up CTX for a subsequent verification operation */
|
||||
if (!X509_STORE_CTX_init(ctx.get(), store, x509, nullptr)) {
|
||||
throw std::runtime_error("Couldn't initialize X509_STORE_CTX. X509_STORE_CTX_init(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Verify X509 */
|
||||
if (!X509_verify_cert(ctx.get())) {
|
||||
throw std::runtime_error("Couldn't verify cert. X509_verify_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
return x509;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QX509::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QX509::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509::generateSelfSignedCertificate - Function generatesand returns self signed X509.
|
||||
/// \param rsa - OpenSSL RSA.
|
||||
/// \param additionalData - Certificate information.
|
||||
/// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it.
|
||||
/// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512().
|
||||
/// \param serialNumber - X509 certificate serial number.
|
||||
/// \param version - X509 certificate version.
|
||||
/// \param notBefore - X509 start date.
|
||||
/// \param notAfter - X509 end date.
|
||||
/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak.
|
||||
///
|
||||
X509* QSimpleCrypto::QX509::generateSelfSignedCertificate(const RSA* rsa, const QMap<QByteArray, QByteArray>& additionalData,
|
||||
const QByteArray& certificateFileName, const EVP_MD* md,
|
||||
const long& serialNumber, const long& version,
|
||||
const long& notBefore, const long& notAfter)
|
||||
{
|
||||
try {
|
||||
/* Initialize X509 */
|
||||
X509* x509 = nullptr;
|
||||
if (!(x509 = X509_new())) {
|
||||
throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize EVP_PKEY */
|
||||
std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY*)> keyStore { EVP_PKEY_new(), EVP_PKEY_free };
|
||||
if (keyStore == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Sign rsa key */
|
||||
if (!EVP_PKEY_assign_RSA(keyStore.get(), rsa)) {
|
||||
throw std::runtime_error("Couldn't assign rsa. EVP_PKEY_assign_RSA(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set certificate serial number. */
|
||||
if (!ASN1_INTEGER_set(X509_get_serialNumber(x509), serialNumber)) {
|
||||
throw std::runtime_error("Couldn't set serial number. ASN1_INTEGER_set(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set certificate version */
|
||||
if (!X509_set_version(x509, version)) {
|
||||
throw std::runtime_error("Couldn't set version. X509_set_version(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Set certificate creation and expiration date */
|
||||
X509_gmtime_adj(X509_get_notBefore(x509), notBefore);
|
||||
X509_gmtime_adj(X509_get_notAfter(x509), notAfter);
|
||||
|
||||
/* Set certificate public key */
|
||||
if (!X509_set_pubkey(x509, keyStore.get())) {
|
||||
throw std::runtime_error("Couldn't set public key. X509_set_pubkey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Initialize X509_NAME */
|
||||
X509_NAME* x509Name = X509_get_subject_name(x509);
|
||||
if (x509Name == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize X509_NAME. X509_NAME(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Add additional data to certificate */
|
||||
QMapIterator<QByteArray, QByteArray> certificateInformationList(additionalData);
|
||||
while (certificateInformationList.hasNext()) {
|
||||
/* Read next item in list */
|
||||
certificateInformationList.next();
|
||||
|
||||
/* Set additional data */
|
||||
if (!X509_NAME_add_entry_by_txt(x509Name, certificateInformationList.key().data(), MBSTRING_UTF8, reinterpret_cast<const unsigned char*>(certificateInformationList.value().data()), -1, -1, 0)) {
|
||||
throw std::runtime_error("Couldn't set additional information. X509_NAME_add_entry_by_txt(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set certificate info */
|
||||
if (!X509_set_issuer_name(x509, x509Name)) {
|
||||
throw std::runtime_error("Couldn't set issuer name. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Sign certificate */
|
||||
if (!X509_sign(x509, keyStore.get(), md)) {
|
||||
throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write certificate file on disk. If needed */
|
||||
if (!certificateFileName.isEmpty()) {
|
||||
/* Initialize BIO */
|
||||
std::unique_ptr<BIO, void (*)(BIO*)> certFile { BIO_new_file(certificateFileName.data(), "w+"), BIO_free_all };
|
||||
if (certFile == nullptr) {
|
||||
throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
|
||||
/* Write file on disk */
|
||||
if (!PEM_write_bio_X509(certFile.get(), x509)) {
|
||||
throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
return x509;
|
||||
} catch (std::exception& exception) {
|
||||
QSimpleCrypto::QX509::error.setError(1, exception.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
QSimpleCrypto::QX509::error.setError(2, "Unknown error!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
176
client/3rd/QSimpleCrypto/sources/QX509Store.cpp
Normal file
176
client/3rd/QSimpleCrypto/sources/QX509Store.cpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution
|
||||
**/
|
||||
|
||||
#include "include/QX509Store.h"
|
||||
|
||||
QSimpleCrypto::QX509Store::QX509Store()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509::addCertificateToStore
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param x509 - OpenSSL X509.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::addCertificateToStore(X509_STORE* store, X509* x509)
|
||||
{
|
||||
if (!X509_STORE_add_cert(store, x509)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add certificate to X509_STORE. X509_STORE_add_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::addLookup
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method)
|
||||
{
|
||||
if (!X509_STORE_add_lookup(store, method)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add lookup to X509_STORE. X509_STORE_add_lookup(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::setCertificateDepth
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::setDepth(X509_STORE* store, const int& depth)
|
||||
{
|
||||
if (!X509_STORE_set_depth(store, depth)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set depth for X509_STORE. X509_STORE_set_depth(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::setFlag
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::setFlag(X509_STORE* store, const unsigned long& flag)
|
||||
{
|
||||
if (!X509_STORE_set_flags(store, flag)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set flag for X509_STORE. X509_STORE_set_flags(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::setFlag
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::setPurpose(X509_STORE* store, const int& purpose)
|
||||
{
|
||||
if (!X509_STORE_set_purpose(store, purpose)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set purpose for X509_STORE. X509_STORE_set_purpose(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::setTrust
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::setTrust(X509_STORE* store, const int& trust)
|
||||
{
|
||||
if (!X509_STORE_set_trust(store, trust)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set trust for X509_STORE. X509_STORE_set_trust(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::setDefaultPaths
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::setDefaultPaths(X509_STORE* store)
|
||||
{
|
||||
if (!X509_STORE_set_default_paths(store)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set default paths for X509_STORE. X509_STORE_set_default_paths(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param fileName - File name. Example: "caCertificate.pem".
|
||||
/// \param dirPath - Path to file. Example: "path/To/File".
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath)
|
||||
{
|
||||
if (!X509_STORE_load_locations(store, fileName, dirPath)) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param file - Qt QFile that will be loaded.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFile& file)
|
||||
{
|
||||
/* Initialize QFileInfo to read information about file */
|
||||
QFileInfo info(file);
|
||||
|
||||
if (!X509_STORE_load_locations(store, info.fileName().toLocal8Bit(), info.absoluteDir().path().toLocal8Bit())) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief QSimpleCrypto::QX509Store::loadLocations
|
||||
/// \param store - OpenSSL X509_STORE.
|
||||
/// \param fileInfo - Qt QFileInfo.
|
||||
/// \return Returns 'true' on success and 'false', if error happened.
|
||||
///
|
||||
bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFileInfo& fileInfo)
|
||||
{
|
||||
if (!X509_STORE_load_locations(store, fileInfo.fileName().toLocal8Bit(), fileInfo.absoluteDir().path().toLocal8Bit())) {
|
||||
QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
856
client/3rd/qrcodegen/qrcodegen.cpp
Normal file
856
client/3rd/qrcodegen/qrcodegen.cpp
Normal file
|
@ -0,0 +1,856 @@
|
|||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include "qrcodegen.hpp"
|
||||
|
||||
using std::int8_t;
|
||||
using std::uint8_t;
|
||||
using std::size_t;
|
||||
using std::vector;
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
||||
/*---- Class QrSegment ----*/
|
||||
|
||||
QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
|
||||
modeBits(mode) {
|
||||
numBitsCharCount[0] = cc0;
|
||||
numBitsCharCount[1] = cc1;
|
||||
numBitsCharCount[2] = cc2;
|
||||
}
|
||||
|
||||
|
||||
int QrSegment::Mode::getModeBits() const {
|
||||
return modeBits;
|
||||
}
|
||||
|
||||
|
||||
int QrSegment::Mode::numCharCountBits(int ver) const {
|
||||
return numBitsCharCount[(ver + 7) / 17];
|
||||
}
|
||||
|
||||
|
||||
const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
|
||||
const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
|
||||
const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
|
||||
const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
|
||||
const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
|
||||
|
||||
|
||||
QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
|
||||
if (data.size() > static_cast<unsigned int>(INT_MAX))
|
||||
throw std::length_error("Data too long");
|
||||
BitBuffer bb;
|
||||
for (uint8_t b : data)
|
||||
bb.appendBits(b, 8);
|
||||
return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
|
||||
}
|
||||
|
||||
|
||||
QrSegment QrSegment::makeNumeric(const char *digits) {
|
||||
BitBuffer bb;
|
||||
int accumData = 0;
|
||||
int accumCount = 0;
|
||||
int charCount = 0;
|
||||
for (; *digits != '\0'; digits++, charCount++) {
|
||||
char c = *digits;
|
||||
if (c < '0' || c > '9')
|
||||
throw std::domain_error("String contains non-numeric characters");
|
||||
accumData = accumData * 10 + (c - '0');
|
||||
accumCount++;
|
||||
if (accumCount == 3) {
|
||||
bb.appendBits(static_cast<uint32_t>(accumData), 10);
|
||||
accumData = 0;
|
||||
accumCount = 0;
|
||||
}
|
||||
}
|
||||
if (accumCount > 0) // 1 or 2 digits remaining
|
||||
bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
|
||||
return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
|
||||
}
|
||||
|
||||
|
||||
QrSegment QrSegment::makeAlphanumeric(const char *text) {
|
||||
BitBuffer bb;
|
||||
int accumData = 0;
|
||||
int accumCount = 0;
|
||||
int charCount = 0;
|
||||
for (; *text != '\0'; text++, charCount++) {
|
||||
const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
|
||||
if (temp == nullptr)
|
||||
throw std::domain_error("String contains unencodable characters in alphanumeric mode");
|
||||
accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
|
||||
accumCount++;
|
||||
if (accumCount == 2) {
|
||||
bb.appendBits(static_cast<uint32_t>(accumData), 11);
|
||||
accumData = 0;
|
||||
accumCount = 0;
|
||||
}
|
||||
}
|
||||
if (accumCount > 0) // 1 character remaining
|
||||
bb.appendBits(static_cast<uint32_t>(accumData), 6);
|
||||
return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
|
||||
}
|
||||
|
||||
|
||||
vector<QrSegment> QrSegment::makeSegments(const char *text) {
|
||||
// Select the most efficient segment encoding automatically
|
||||
vector<QrSegment> result;
|
||||
if (*text == '\0'); // Leave result empty
|
||||
else if (isNumeric(text))
|
||||
result.push_back(makeNumeric(text));
|
||||
else if (isAlphanumeric(text))
|
||||
result.push_back(makeAlphanumeric(text));
|
||||
else {
|
||||
vector<uint8_t> bytes;
|
||||
for (; *text != '\0'; text++)
|
||||
bytes.push_back(static_cast<uint8_t>(*text));
|
||||
result.push_back(makeBytes(bytes));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
QrSegment QrSegment::makeEci(long assignVal) {
|
||||
BitBuffer bb;
|
||||
if (assignVal < 0)
|
||||
throw std::domain_error("ECI assignment value out of range");
|
||||
else if (assignVal < (1 << 7))
|
||||
bb.appendBits(static_cast<uint32_t>(assignVal), 8);
|
||||
else if (assignVal < (1 << 14)) {
|
||||
bb.appendBits(2, 2);
|
||||
bb.appendBits(static_cast<uint32_t>(assignVal), 14);
|
||||
} else if (assignVal < 1000000L) {
|
||||
bb.appendBits(6, 3);
|
||||
bb.appendBits(static_cast<uint32_t>(assignVal), 21);
|
||||
} else
|
||||
throw std::domain_error("ECI assignment value out of range");
|
||||
return QrSegment(Mode::ECI, 0, std::move(bb));
|
||||
}
|
||||
|
||||
|
||||
QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt) :
|
||||
mode(&md),
|
||||
numChars(numCh),
|
||||
data(dt) {
|
||||
if (numCh < 0)
|
||||
throw std::domain_error("Invalid value");
|
||||
}
|
||||
|
||||
|
||||
QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) :
|
||||
mode(&md),
|
||||
numChars(numCh),
|
||||
data(std::move(dt)) {
|
||||
if (numCh < 0)
|
||||
throw std::domain_error("Invalid value");
|
||||
}
|
||||
|
||||
|
||||
int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
|
||||
int result = 0;
|
||||
for (const QrSegment &seg : segs) {
|
||||
int ccbits = seg.mode->numCharCountBits(version);
|
||||
if (seg.numChars >= (1L << ccbits))
|
||||
return -1; // The segment's length doesn't fit the field's bit width
|
||||
if (4 + ccbits > INT_MAX - result)
|
||||
return -1; // The sum will overflow an int type
|
||||
result += 4 + ccbits;
|
||||
if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
|
||||
return -1; // The sum will overflow an int type
|
||||
result += static_cast<int>(seg.data.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool QrSegment::isNumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
char c = *text;
|
||||
if (c < '0' || c > '9')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QrSegment::isAlphanumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const QrSegment::Mode &QrSegment::getMode() const {
|
||||
return *mode;
|
||||
}
|
||||
|
||||
|
||||
int QrSegment::getNumChars() const {
|
||||
return numChars;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<bool> &QrSegment::getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
||||
|
||||
|
||||
|
||||
/*---- Class QrCode ----*/
|
||||
|
||||
int QrCode::getFormatBits(Ecc ecl) {
|
||||
switch (ecl) {
|
||||
case Ecc::LOW : return 1;
|
||||
case Ecc::MEDIUM : return 0;
|
||||
case Ecc::QUARTILE: return 3;
|
||||
case Ecc::HIGH : return 2;
|
||||
default: throw std::logic_error("Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QrCode QrCode::encodeText(const char *text, Ecc ecl) {
|
||||
vector<QrSegment> segs = QrSegment::makeSegments(text);
|
||||
return encodeSegments(segs, ecl);
|
||||
}
|
||||
|
||||
|
||||
QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
|
||||
vector<QrSegment> segs{QrSegment::makeBytes(data)};
|
||||
return encodeSegments(segs, ecl);
|
||||
}
|
||||
|
||||
|
||||
QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
|
||||
int minVersion, int maxVersion, int mask, bool boostEcl) {
|
||||
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
|
||||
throw std::invalid_argument("Invalid value");
|
||||
|
||||
// Find the minimal version number to use
|
||||
int version, dataUsedBits;
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment::getTotalBits(segs, version);
|
||||
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
if (version >= maxVersion) { // All versions in the range could not fit the given data
|
||||
std::ostringstream sb;
|
||||
if (dataUsedBits == -1)
|
||||
sb << "Segment too long";
|
||||
else {
|
||||
sb << "Data length = " << dataUsedBits << " bits, ";
|
||||
sb << "Max capacity = " << dataCapacityBits << " bits";
|
||||
}
|
||||
throw data_too_long(sb.str());
|
||||
}
|
||||
}
|
||||
assert(dataUsedBits != -1);
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
|
||||
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
|
||||
ecl = newEcl;
|
||||
}
|
||||
|
||||
// Concatenate all segments to create the data bit string
|
||||
BitBuffer bb;
|
||||
for (const QrSegment &seg : segs) {
|
||||
bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4);
|
||||
bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
|
||||
bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
|
||||
}
|
||||
assert(bb.size() == static_cast<unsigned int>(dataUsedBits));
|
||||
|
||||
// Add terminator and pad up to a byte if applicable
|
||||
size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
|
||||
assert(bb.size() <= dataCapacityBits);
|
||||
bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
|
||||
bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
|
||||
assert(bb.size() % 8 == 0);
|
||||
|
||||
// Pad with alternating bytes until data capacity is reached
|
||||
for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
||||
bb.appendBits(padByte, 8);
|
||||
|
||||
// Pack bits into bytes in big endian
|
||||
vector<uint8_t> dataCodewords(bb.size() / 8);
|
||||
for (size_t i = 0; i < bb.size(); i++)
|
||||
dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
|
||||
|
||||
// Create the QR Code object
|
||||
return QrCode(version, ecl, dataCodewords, mask);
|
||||
}
|
||||
|
||||
|
||||
QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
|
||||
// Initialize fields and check arguments
|
||||
version(ver),
|
||||
errorCorrectionLevel(ecl) {
|
||||
if (ver < MIN_VERSION || ver > MAX_VERSION)
|
||||
throw std::domain_error("Version value out of range");
|
||||
if (msk < -1 || msk > 7)
|
||||
throw std::domain_error("Mask value out of range");
|
||||
size = ver * 4 + 17;
|
||||
size_t sz = static_cast<size_t>(size);
|
||||
modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all light
|
||||
isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
|
||||
|
||||
// Compute ECC, draw modules
|
||||
drawFunctionPatterns();
|
||||
const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
|
||||
drawCodewords(allCodewords);
|
||||
|
||||
// Do masking
|
||||
if (msk == -1) { // Automatically choose best mask
|
||||
long minPenalty = LONG_MAX;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
applyMask(i);
|
||||
drawFormatBits(i);
|
||||
long penalty = getPenaltyScore();
|
||||
if (penalty < minPenalty) {
|
||||
msk = i;
|
||||
minPenalty = penalty;
|
||||
}
|
||||
applyMask(i); // Undoes the mask due to XOR
|
||||
}
|
||||
}
|
||||
assert(0 <= msk && msk <= 7);
|
||||
mask = msk;
|
||||
applyMask(msk); // Apply the final choice of mask
|
||||
drawFormatBits(msk); // Overwrite old format bits
|
||||
|
||||
isFunction.clear();
|
||||
isFunction.shrink_to_fit();
|
||||
}
|
||||
|
||||
|
||||
int QrCode::getVersion() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
int QrCode::getSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
|
||||
return errorCorrectionLevel;
|
||||
}
|
||||
|
||||
|
||||
int QrCode::getMask() const {
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
bool QrCode::getModule(int x, int y) const {
|
||||
return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawFunctionPatterns() {
|
||||
// Draw horizontal and vertical timing patterns
|
||||
for (int i = 0; i < size; i++) {
|
||||
setFunctionModule(6, i, i % 2 == 0);
|
||||
setFunctionModule(i, 6, i % 2 == 0);
|
||||
}
|
||||
|
||||
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
|
||||
drawFinderPattern(3, 3);
|
||||
drawFinderPattern(size - 4, 3);
|
||||
drawFinderPattern(3, size - 4);
|
||||
|
||||
// Draw numerous alignment patterns
|
||||
const vector<int> alignPatPos = getAlignmentPatternPositions();
|
||||
size_t numAlign = alignPatPos.size();
|
||||
for (size_t i = 0; i < numAlign; i++) {
|
||||
for (size_t j = 0; j < numAlign; j++) {
|
||||
// Don't draw on the three finder corners
|
||||
if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
|
||||
drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw configuration data
|
||||
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
|
||||
drawVersion();
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawFormatBits(int msk) {
|
||||
// Calculate error correction code and pack bits
|
||||
int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3
|
||||
int rem = data;
|
||||
for (int i = 0; i < 10; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
|
||||
int bits = (data << 10 | rem) ^ 0x5412; // uint15
|
||||
assert(bits >> 15 == 0);
|
||||
|
||||
// Draw first copy
|
||||
for (int i = 0; i <= 5; i++)
|
||||
setFunctionModule(8, i, getBit(bits, i));
|
||||
setFunctionModule(8, 7, getBit(bits, 6));
|
||||
setFunctionModule(8, 8, getBit(bits, 7));
|
||||
setFunctionModule(7, 8, getBit(bits, 8));
|
||||
for (int i = 9; i < 15; i++)
|
||||
setFunctionModule(14 - i, 8, getBit(bits, i));
|
||||
|
||||
// Draw second copy
|
||||
for (int i = 0; i < 8; i++)
|
||||
setFunctionModule(size - 1 - i, 8, getBit(bits, i));
|
||||
for (int i = 8; i < 15; i++)
|
||||
setFunctionModule(8, size - 15 + i, getBit(bits, i));
|
||||
setFunctionModule(8, size - 8, true); // Always dark
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawVersion() {
|
||||
if (version < 7)
|
||||
return;
|
||||
|
||||
// Calculate error correction code and pack bits
|
||||
int rem = version; // version is uint6, in the range [7, 40]
|
||||
for (int i = 0; i < 12; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
|
||||
long bits = static_cast<long>(version) << 12 | rem; // uint18
|
||||
assert(bits >> 18 == 0);
|
||||
|
||||
// Draw two copies
|
||||
for (int i = 0; i < 18; i++) {
|
||||
bool bit = getBit(bits, i);
|
||||
int a = size - 11 + i % 3;
|
||||
int b = i / 3;
|
||||
setFunctionModule(a, b, bit);
|
||||
setFunctionModule(b, a, bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawFinderPattern(int x, int y) {
|
||||
for (int dy = -4; dy <= 4; dy++) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm
|
||||
int xx = x + dx, yy = y + dy;
|
||||
if (0 <= xx && xx < size && 0 <= yy && yy < size)
|
||||
setFunctionModule(xx, yy, dist != 2 && dist != 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawAlignmentPattern(int x, int y) {
|
||||
for (int dy = -2; dy <= 2; dy++) {
|
||||
for (int dx = -2; dx <= 2; dx++)
|
||||
setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QrCode::setFunctionModule(int x, int y, bool isDark) {
|
||||
size_t ux = static_cast<size_t>(x);
|
||||
size_t uy = static_cast<size_t>(y);
|
||||
modules .at(uy).at(ux) = isDark;
|
||||
isFunction.at(uy).at(ux) = true;
|
||||
}
|
||||
|
||||
|
||||
bool QrCode::module(int x, int y) const {
|
||||
return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x));
|
||||
}
|
||||
|
||||
|
||||
vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
|
||||
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
|
||||
throw std::invalid_argument("Invalid argument");
|
||||
|
||||
// Calculate parameter numbers
|
||||
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
|
||||
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast<int>(errorCorrectionLevel)][version];
|
||||
int rawCodewords = getNumRawDataModules(version) / 8;
|
||||
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
|
||||
int shortBlockLen = rawCodewords / numBlocks;
|
||||
|
||||
// Split data into blocks and append ECC to each block
|
||||
vector<vector<uint8_t> > blocks;
|
||||
const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
|
||||
for (int i = 0, k = 0; i < numBlocks; i++) {
|
||||
vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
|
||||
k += static_cast<int>(dat.size());
|
||||
const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
|
||||
if (i < numShortBlocks)
|
||||
dat.push_back(0);
|
||||
dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
|
||||
blocks.push_back(std::move(dat));
|
||||
}
|
||||
|
||||
// Interleave (not concatenate) the bytes from every block into a single sequence
|
||||
vector<uint8_t> result;
|
||||
for (size_t i = 0; i < blocks.at(0).size(); i++) {
|
||||
for (size_t j = 0; j < blocks.size(); j++) {
|
||||
// Skip the padding byte in short blocks
|
||||
if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks))
|
||||
result.push_back(blocks.at(j).at(i));
|
||||
}
|
||||
}
|
||||
assert(result.size() == static_cast<unsigned int>(rawCodewords));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawCodewords(const vector<uint8_t> &data) {
|
||||
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
|
||||
throw std::invalid_argument("Invalid argument");
|
||||
|
||||
size_t i = 0; // Bit index into the data
|
||||
// Do the funny zigzag scan
|
||||
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
|
||||
if (right == 6)
|
||||
right = 5;
|
||||
for (int vert = 0; vert < size; vert++) { // Vertical counter
|
||||
for (int j = 0; j < 2; j++) {
|
||||
size_t x = static_cast<size_t>(right - j); // Actual x coordinate
|
||||
bool upward = ((right + 1) & 2) == 0;
|
||||
size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert); // Actual y coordinate
|
||||
if (!isFunction.at(y).at(x) && i < data.size() * 8) {
|
||||
modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7));
|
||||
i++;
|
||||
}
|
||||
// If this QR Code has any remainder bits (0 to 7), they were assigned as
|
||||
// 0/false/light by the constructor and are left unchanged by this method
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(i == data.size() * 8);
|
||||
}
|
||||
|
||||
|
||||
void QrCode::applyMask(int msk) {
|
||||
if (msk < 0 || msk > 7)
|
||||
throw std::domain_error("Mask value out of range");
|
||||
size_t sz = static_cast<size_t>(size);
|
||||
for (size_t y = 0; y < sz; y++) {
|
||||
for (size_t x = 0; x < sz; x++) {
|
||||
bool invert;
|
||||
switch (msk) {
|
||||
case 0: invert = (x + y) % 2 == 0; break;
|
||||
case 1: invert = y % 2 == 0; break;
|
||||
case 2: invert = x % 3 == 0; break;
|
||||
case 3: invert = (x + y) % 3 == 0; break;
|
||||
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
|
||||
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
|
||||
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
|
||||
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
|
||||
default: throw std::logic_error("Unreachable");
|
||||
}
|
||||
modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long QrCode::getPenaltyScore() const {
|
||||
long result = 0;
|
||||
|
||||
// Adjacent modules in row having same color, and finder-like patterns
|
||||
for (int y = 0; y < size; y++) {
|
||||
bool runColor = false;
|
||||
int runX = 0;
|
||||
std::array<int,7> runHistory = {};
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (module(x, y) == runColor) {
|
||||
runX++;
|
||||
if (runX == 5)
|
||||
result += PENALTY_N1;
|
||||
else if (runX > 5)
|
||||
result++;
|
||||
} else {
|
||||
finderPenaltyAddHistory(runX, runHistory);
|
||||
if (!runColor)
|
||||
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
|
||||
runColor = module(x, y);
|
||||
runX = 1;
|
||||
}
|
||||
}
|
||||
result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
|
||||
}
|
||||
// Adjacent modules in column having same color, and finder-like patterns
|
||||
for (int x = 0; x < size; x++) {
|
||||
bool runColor = false;
|
||||
int runY = 0;
|
||||
std::array<int,7> runHistory = {};
|
||||
for (int y = 0; y < size; y++) {
|
||||
if (module(x, y) == runColor) {
|
||||
runY++;
|
||||
if (runY == 5)
|
||||
result += PENALTY_N1;
|
||||
else if (runY > 5)
|
||||
result++;
|
||||
} else {
|
||||
finderPenaltyAddHistory(runY, runHistory);
|
||||
if (!runColor)
|
||||
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
|
||||
runColor = module(x, y);
|
||||
runY = 1;
|
||||
}
|
||||
}
|
||||
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
|
||||
}
|
||||
|
||||
// 2*2 blocks of modules having same color
|
||||
for (int y = 0; y < size - 1; y++) {
|
||||
for (int x = 0; x < size - 1; x++) {
|
||||
bool color = module(x, y);
|
||||
if ( color == module(x + 1, y) &&
|
||||
color == module(x, y + 1) &&
|
||||
color == module(x + 1, y + 1))
|
||||
result += PENALTY_N2;
|
||||
}
|
||||
}
|
||||
|
||||
// Balance of dark and light modules
|
||||
int dark = 0;
|
||||
for (const vector<bool> &row : modules) {
|
||||
for (bool color : row) {
|
||||
if (color)
|
||||
dark++;
|
||||
}
|
||||
}
|
||||
int total = size * size; // Note that size is odd, so dark/total != 1/2
|
||||
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
|
||||
int k = static_cast<int>((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1;
|
||||
assert(0 <= k && k <= 9);
|
||||
result += k * PENALTY_N4;
|
||||
assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vector<int> QrCode::getAlignmentPatternPositions() const {
|
||||
if (version == 1)
|
||||
return vector<int>();
|
||||
else {
|
||||
int numAlign = version / 7 + 2;
|
||||
int step = (version == 32) ? 26 :
|
||||
(version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;
|
||||
vector<int> result;
|
||||
for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
|
||||
result.insert(result.begin(), pos);
|
||||
result.insert(result.begin(), 6);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int QrCode::getNumRawDataModules(int ver) {
|
||||
if (ver < MIN_VERSION || ver > MAX_VERSION)
|
||||
throw std::domain_error("Version number out of range");
|
||||
int result = (16 * ver + 128) * ver + 64;
|
||||
if (ver >= 2) {
|
||||
int numAlign = ver / 7 + 2;
|
||||
result -= (25 * numAlign - 10) * numAlign - 55;
|
||||
if (ver >= 7)
|
||||
result -= 36;
|
||||
}
|
||||
assert(208 <= result && result <= 29648);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
|
||||
return getNumRawDataModules(ver) / 8
|
||||
- ECC_CODEWORDS_PER_BLOCK [static_cast<int>(ecl)][ver]
|
||||
* NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
|
||||
}
|
||||
|
||||
|
||||
vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
|
||||
if (degree < 1 || degree > 255)
|
||||
throw std::domain_error("Degree out of range");
|
||||
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
|
||||
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
|
||||
vector<uint8_t> result(static_cast<size_t>(degree));
|
||||
result.at(result.size() - 1) = 1; // Start off with the monomial x^0
|
||||
|
||||
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
|
||||
// and drop the highest monomial term which is always 1x^degree.
|
||||
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
|
||||
uint8_t root = 1;
|
||||
for (int i = 0; i < degree; i++) {
|
||||
// Multiply the current product by (x - r^i)
|
||||
for (size_t j = 0; j < result.size(); j++) {
|
||||
result.at(j) = reedSolomonMultiply(result.at(j), root);
|
||||
if (j + 1 < result.size())
|
||||
result.at(j) ^= result.at(j + 1);
|
||||
}
|
||||
root = reedSolomonMultiply(root, 0x02);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
|
||||
vector<uint8_t> result(divisor.size());
|
||||
for (uint8_t b : data) { // Polynomial division
|
||||
uint8_t factor = b ^ result.at(0);
|
||||
result.erase(result.begin());
|
||||
result.push_back(0);
|
||||
for (size_t i = 0; i < result.size(); i++)
|
||||
result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
|
||||
// Russian peasant multiplication
|
||||
int z = 0;
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
z = (z << 1) ^ ((z >> 7) * 0x11D);
|
||||
z ^= ((y >> i) & 1) * x;
|
||||
}
|
||||
assert(z >> 8 == 0);
|
||||
return static_cast<uint8_t>(z);
|
||||
}
|
||||
|
||||
|
||||
int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
|
||||
int n = runHistory.at(1);
|
||||
assert(n <= size * 3);
|
||||
bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
|
||||
return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
|
||||
+ (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const {
|
||||
if (currentRunColor) { // Terminate dark run
|
||||
finderPenaltyAddHistory(currentRunLength, runHistory);
|
||||
currentRunLength = 0;
|
||||
}
|
||||
currentRunLength += size; // Add light border to final run
|
||||
finderPenaltyAddHistory(currentRunLength, runHistory);
|
||||
return finderPenaltyCountPatterns(runHistory);
|
||||
}
|
||||
|
||||
|
||||
void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const {
|
||||
if (runHistory.at(0) == 0)
|
||||
currentRunLength += size; // Add light border to initial run
|
||||
std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
|
||||
runHistory.at(0) = currentRunLength;
|
||||
}
|
||||
|
||||
|
||||
bool QrCode::getBit(long x, int i) {
|
||||
return ((x >> i) & 1) != 0;
|
||||
}
|
||||
|
||||
|
||||
/*---- Tables of constants ----*/
|
||||
|
||||
const int QrCode::PENALTY_N1 = 3;
|
||||
const int QrCode::PENALTY_N2 = 3;
|
||||
const int QrCode::PENALTY_N3 = 40;
|
||||
const int QrCode::PENALTY_N4 = 10;
|
||||
|
||||
|
||||
const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
|
||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||
{-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
|
||||
{-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
|
||||
{-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
|
||||
{-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
|
||||
};
|
||||
|
||||
const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
|
||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
|
||||
{-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
|
||||
{-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
|
||||
{-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
|
||||
};
|
||||
|
||||
|
||||
data_too_long::data_too_long(const std::string &msg) :
|
||||
std::length_error(msg) {}
|
||||
|
||||
|
||||
|
||||
/*---- Class BitBuffer ----*/
|
||||
|
||||
BitBuffer::BitBuffer()
|
||||
: std::vector<bool>() {}
|
||||
|
||||
|
||||
void BitBuffer::appendBits(std::uint32_t val, int len) {
|
||||
if (len < 0 || len > 31 || val >> len != 0)
|
||||
throw std::domain_error("Value out of range");
|
||||
for (int i = len - 1; i >= 0; i--) // Append bit by bit
|
||||
this->push_back(((val >> i) & 1) != 0);
|
||||
}
|
||||
|
||||
std::string toSvgString(const QrCode &qr, int border) {
|
||||
if (border < 0)
|
||||
throw std::domain_error("Border must be non-negative");
|
||||
if (border > INT_MAX / 2 || border * 2 > INT_MAX - qr.getSize())
|
||||
throw std::overflow_error("Border too large");
|
||||
|
||||
std::ostringstream sb;
|
||||
sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
|
||||
sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
|
||||
sb << (qr.getSize() + border * 2) << " " << (qr.getSize() + border * 2) << "\" stroke=\"none\">\n";
|
||||
sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
|
||||
sb << "\t<path d=\"";
|
||||
for (int y = 0; y < qr.getSize(); y++) {
|
||||
for (int x = 0; x < qr.getSize(); x++) {
|
||||
if (qr.getModule(x, y)) {
|
||||
if (x != 0 || y != 0)
|
||||
sb << " ";
|
||||
sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
|
||||
}
|
||||
}
|
||||
}
|
||||
sb << "\" fill=\"#000000\"/>\n";
|
||||
sb << "</svg>\n";
|
||||
return sb.str();
|
||||
}
|
||||
}
|
551
client/3rd/qrcodegen/qrcodegen.hpp
Normal file
551
client/3rd/qrcodegen/qrcodegen.hpp
Normal file
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
||||
/*
|
||||
* A segment of character/binary/control data in a QR Code symbol.
|
||||
* Instances of this class are immutable.
|
||||
* The mid-level way to create a segment is to take the payload data
|
||||
* and call a static factory function such as QrSegment::makeNumeric().
|
||||
* The low-level way to create a segment is to custom-make the bit buffer
|
||||
* and call the QrSegment() constructor with appropriate values.
|
||||
* This segment class imposes no length restrictions, but QR Codes have restrictions.
|
||||
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
|
||||
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
|
||||
*/
|
||||
class QrSegment final {
|
||||
|
||||
/*---- Public helper enumeration ----*/
|
||||
|
||||
/*
|
||||
* Describes how a segment's data bits are interpreted. Immutable.
|
||||
*/
|
||||
public: class Mode final {
|
||||
|
||||
/*-- Constants --*/
|
||||
|
||||
public: static const Mode NUMERIC;
|
||||
public: static const Mode ALPHANUMERIC;
|
||||
public: static const Mode BYTE;
|
||||
public: static const Mode KANJI;
|
||||
public: static const Mode ECI;
|
||||
|
||||
|
||||
/*-- Fields --*/
|
||||
|
||||
// The mode indicator bits, which is a uint4 value (range 0 to 15).
|
||||
private: int modeBits;
|
||||
|
||||
// Number of character count bits for three different version ranges.
|
||||
private: int numBitsCharCount[3];
|
||||
|
||||
|
||||
/*-- Constructor --*/
|
||||
|
||||
private: Mode(int mode, int cc0, int cc1, int cc2);
|
||||
|
||||
|
||||
/*-- Methods --*/
|
||||
|
||||
/*
|
||||
* (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
|
||||
*/
|
||||
public: int getModeBits() const;
|
||||
|
||||
/*
|
||||
* (Package-private) Returns the bit width of the character count field for a segment in
|
||||
* this mode in a QR Code at the given version number. The result is in the range [0, 16].
|
||||
*/
|
||||
public: int numCharCountBits(int ver) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*---- Static factory functions (mid level) ----*/
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given binary data encoded in
|
||||
* byte mode. All input byte vectors are acceptable. Any text string
|
||||
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
|
||||
*/
|
||||
public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
||||
*/
|
||||
public: static QrSegment makeNumeric(const char *digits);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given text string encoded in alphanumeric mode.
|
||||
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
|
||||
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
public: static QrSegment makeAlphanumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a list of zero or more segments to represent the given text string. The result
|
||||
* may use various segment modes and switch modes to optimize the length of the bit stream.
|
||||
*/
|
||||
public: static std::vector<QrSegment> makeSegments(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing an Extended Channel Interpretation
|
||||
* (ECI) designator with the given assignment value.
|
||||
*/
|
||||
public: static QrSegment makeEci(long assignVal);
|
||||
|
||||
|
||||
/*---- Public static helper functions ----*/
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in numeric mode.
|
||||
* A string is encodable iff each character is in the range 0 to 9.
|
||||
*/
|
||||
public: static bool isNumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
|
||||
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
|
||||
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
public: static bool isAlphanumeric(const char *text);
|
||||
|
||||
|
||||
|
||||
/*---- Instance fields ----*/
|
||||
|
||||
/* The mode indicator of this segment. Accessed through getMode(). */
|
||||
private: const Mode *mode;
|
||||
|
||||
/* The length of this segment's unencoded data. Measured in characters for
|
||||
* numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
|
||||
* Always zero or positive. Not the same as the data's bit length.
|
||||
* Accessed through getNumChars(). */
|
||||
private: int numChars;
|
||||
|
||||
/* The data bits of this segment. Accessed through getData(). */
|
||||
private: std::vector<bool> data;
|
||||
|
||||
|
||||
/*---- Constructors (low level) ----*/
|
||||
|
||||
/*
|
||||
* Creates a new QR Code segment with the given attributes and data.
|
||||
* The character count (numCh) must agree with the mode and the bit buffer length,
|
||||
* but the constraint isn't checked. The given bit buffer is copied and stored.
|
||||
*/
|
||||
public: QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt);
|
||||
|
||||
|
||||
/*
|
||||
* Creates a new QR Code segment with the given parameters and data.
|
||||
* The character count (numCh) must agree with the mode and the bit buffer length,
|
||||
* but the constraint isn't checked. The given bit buffer is moved and stored.
|
||||
*/
|
||||
public: QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt);
|
||||
|
||||
|
||||
/*---- Methods ----*/
|
||||
|
||||
/*
|
||||
* Returns the mode field of this segment.
|
||||
*/
|
||||
public: const Mode &getMode() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the character count field of this segment.
|
||||
*/
|
||||
public: int getNumChars() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the data bits of this segment.
|
||||
*/
|
||||
public: const std::vector<bool> &getData() const;
|
||||
|
||||
|
||||
// (Package-private) Calculates the number of bits needed to encode the given segments at
|
||||
// the given version. Returns a non-negative number if successful. Otherwise returns -1 if a
|
||||
// segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
|
||||
public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
|
||||
|
||||
|
||||
/*---- Private constant ----*/
|
||||
|
||||
/* The set of all legal characters in alphanumeric mode, where
|
||||
* each character value maps to the index in the string. */
|
||||
private: static const char *ALPHANUMERIC_CHARSET;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A QR Code symbol, which is a type of two-dimension barcode.
|
||||
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
|
||||
* Instances of this class represent an immutable square grid of dark and light cells.
|
||||
* The class provides static factory functions to create a QR Code from text or binary data.
|
||||
* The class covers the QR Code Model 2 specification, supporting all versions (sizes)
|
||||
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
|
||||
*
|
||||
* Ways to create a QR Code object:
|
||||
* - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary().
|
||||
* - Mid level: Custom-make the list of segments and call QrCode::encodeSegments().
|
||||
* - Low level: Custom-make the array of data codeword bytes (including
|
||||
* segment headers and final padding, excluding error correction codewords),
|
||||
* supply the appropriate version number, and call the QrCode() constructor.
|
||||
* (Note that all ways require supplying the desired error correction level.)
|
||||
*/
|
||||
class QrCode final {
|
||||
|
||||
/*---- Public helper enumeration ----*/
|
||||
|
||||
/*
|
||||
* The error correction level in a QR Code symbol.
|
||||
*/
|
||||
public: enum class Ecc {
|
||||
LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
|
||||
MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
|
||||
QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
|
||||
HIGH , // The QR Code can tolerate about 30% erroneous codewords
|
||||
};
|
||||
|
||||
|
||||
// Returns a value in the range 0 to 3 (unsigned 2-bit integer).
|
||||
private: static int getFormatBits(Ecc ecl);
|
||||
|
||||
|
||||
|
||||
/*---- Static factory functions (high level) ----*/
|
||||
|
||||
/*
|
||||
* Returns a QR Code representing the given Unicode text string at the given error correction level.
|
||||
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
|
||||
* UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
|
||||
* QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
|
||||
* the ecl argument if it can be done without increasing the version.
|
||||
*/
|
||||
public: static QrCode encodeText(const char *text, Ecc ecl);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a QR Code representing the given binary data at the given error correction level.
|
||||
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
|
||||
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
||||
*/
|
||||
public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
|
||||
|
||||
|
||||
/*---- Static factory functions (mid level) ----*/
|
||||
|
||||
/*
|
||||
* Returns a QR Code representing the given segments with the given encoding parameters.
|
||||
* The smallest possible QR Code version within the given range is automatically
|
||||
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
|
||||
* may be higher than the ecl argument if it can be done without increasing the
|
||||
* version. The mask number is either between 0 to 7 (inclusive) to force that
|
||||
* mask, or -1 to automatically choose an appropriate mask (which may be slow).
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* between modes (such as alphanumeric and byte) to encode text in less space.
|
||||
* This is a mid-level API; the high-level API is encodeText() and encodeBinary().
|
||||
*/
|
||||
public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
|
||||
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
|
||||
|
||||
|
||||
|
||||
/*---- Instance fields ----*/
|
||||
|
||||
// Immutable scalar parameters:
|
||||
|
||||
/* The version number of this QR Code, which is between 1 and 40 (inclusive).
|
||||
* This determines the size of this barcode. */
|
||||
private: int version;
|
||||
|
||||
/* The width and height of this QR Code, measured in modules, between
|
||||
* 21 and 177 (inclusive). This is equal to version * 4 + 17. */
|
||||
private: int size;
|
||||
|
||||
/* The error correction level used in this QR Code. */
|
||||
private: Ecc errorCorrectionLevel;
|
||||
|
||||
/* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
|
||||
* Even if a QR Code is created with automatic masking requested (mask = -1),
|
||||
* the resulting object still has a mask value between 0 and 7. */
|
||||
private: int mask;
|
||||
|
||||
// Private grids of modules/pixels, with dimensions of size*size:
|
||||
|
||||
// The modules of this QR Code (false = light, true = dark).
|
||||
// Immutable after constructor finishes. Accessed through getModule().
|
||||
private: std::vector<std::vector<bool> > modules;
|
||||
|
||||
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
|
||||
private: std::vector<std::vector<bool> > isFunction;
|
||||
|
||||
|
||||
|
||||
/*---- Constructor (low level) ----*/
|
||||
|
||||
/*
|
||||
* Creates a new QR Code with the given version number,
|
||||
* error correction level, data codeword bytes, and mask number.
|
||||
* This is a low-level API that most users should not use directly.
|
||||
* A mid-level API is the encodeSegments() function.
|
||||
*/
|
||||
public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
|
||||
|
||||
|
||||
|
||||
/*---- Public instance methods ----*/
|
||||
|
||||
/*
|
||||
* Returns this QR Code's version, in the range [1, 40].
|
||||
*/
|
||||
public: int getVersion() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns this QR Code's size, in the range [21, 177].
|
||||
*/
|
||||
public: int getSize() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns this QR Code's error correction level.
|
||||
*/
|
||||
public: Ecc getErrorCorrectionLevel() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns this QR Code's mask, in the range [0, 7].
|
||||
*/
|
||||
public: int getMask() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the color of the module (pixel) at the given coordinates, which is false
|
||||
* for light or true for dark. The top left corner has the coordinates (x=0, y=0).
|
||||
* If the given coordinates are out of bounds, then false (light) is returned.
|
||||
*/
|
||||
public: bool getModule(int x, int y) const;
|
||||
|
||||
|
||||
|
||||
/*---- Private helper methods for constructor: Drawing function modules ----*/
|
||||
|
||||
// Reads this object's version field, and draws and marks all function modules.
|
||||
private: void drawFunctionPatterns();
|
||||
|
||||
|
||||
// Draws two copies of the format bits (with its own error correction code)
|
||||
// based on the given mask and this object's error correction level field.
|
||||
private: void drawFormatBits(int msk);
|
||||
|
||||
|
||||
// Draws two copies of the version bits (with its own error correction code),
|
||||
// based on this object's version field, iff 7 <= version <= 40.
|
||||
private: void drawVersion();
|
||||
|
||||
|
||||
// Draws a 9*9 finder pattern including the border separator,
|
||||
// with the center module at (x, y). Modules can be out of bounds.
|
||||
private: void drawFinderPattern(int x, int y);
|
||||
|
||||
|
||||
// Draws a 5*5 alignment pattern, with the center module
|
||||
// at (x, y). All modules must be in bounds.
|
||||
private: void drawAlignmentPattern(int x, int y);
|
||||
|
||||
|
||||
// Sets the color of a module and marks it as a function module.
|
||||
// Only used by the constructor. Coordinates must be in bounds.
|
||||
private: void setFunctionModule(int x, int y, bool isDark);
|
||||
|
||||
|
||||
// Returns the color of the module at the given coordinates, which must be in range.
|
||||
private: bool module(int x, int y) const;
|
||||
|
||||
|
||||
/*---- Private helper methods for constructor: Codewords and masking ----*/
|
||||
|
||||
// Returns a new byte string representing the given data with the appropriate error correction
|
||||
// codewords appended to it, based on this object's version and error correction level.
|
||||
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
|
||||
|
||||
|
||||
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
|
||||
// data area of this QR Code. Function modules need to be marked off before this is called.
|
||||
private: void drawCodewords(const std::vector<std::uint8_t> &data);
|
||||
|
||||
|
||||
// XORs the codeword modules in this QR Code with the given mask pattern.
|
||||
// The function modules must be marked and the codeword bits must be drawn
|
||||
// before masking. Due to the arithmetic of XOR, calling applyMask() with
|
||||
// the same mask value a second time will undo the mask. A final well-formed
|
||||
// QR Code needs exactly one (not zero, two, etc.) mask applied.
|
||||
private: void applyMask(int msk);
|
||||
|
||||
|
||||
// Calculates and returns the penalty score based on state of this QR Code's current modules.
|
||||
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
|
||||
private: long getPenaltyScore() const;
|
||||
|
||||
|
||||
|
||||
/*---- Private helper functions ----*/
|
||||
|
||||
// Returns an ascending list of positions of alignment patterns for this version number.
|
||||
// Each position is in the range [0,177), and are used on both the x and y axes.
|
||||
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
|
||||
private: std::vector<int> getAlignmentPatternPositions() const;
|
||||
|
||||
|
||||
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
|
||||
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
|
||||
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
|
||||
private: static int getNumRawDataModules(int ver);
|
||||
|
||||
|
||||
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
|
||||
// QR Code of the given version number and error correction level, with remainder bits discarded.
|
||||
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
|
||||
private: static int getNumDataCodewords(int ver, Ecc ecl);
|
||||
|
||||
|
||||
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
|
||||
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
||||
private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
|
||||
|
||||
|
||||
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
|
||||
private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
|
||||
|
||||
|
||||
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
|
||||
// All inputs are valid. This could be implemented as a 256*256 lookup table.
|
||||
private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
|
||||
|
||||
|
||||
// Can only be called immediately after a light run is added, and
|
||||
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
|
||||
private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const;
|
||||
|
||||
|
||||
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
|
||||
private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const;
|
||||
|
||||
|
||||
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
|
||||
private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
|
||||
|
||||
|
||||
// Returns true iff the i'th bit of x is set to 1.
|
||||
private: static bool getBit(long x, int i);
|
||||
|
||||
|
||||
/*---- Constants and tables ----*/
|
||||
|
||||
// The minimum version number supported in the QR Code Model 2 standard.
|
||||
public: static constexpr int MIN_VERSION = 1;
|
||||
|
||||
// The maximum version number supported in the QR Code Model 2 standard.
|
||||
public: static constexpr int MAX_VERSION = 40;
|
||||
|
||||
|
||||
// For use in getPenaltyScore(), when evaluating which mask is best.
|
||||
private: static const int PENALTY_N1;
|
||||
private: static const int PENALTY_N2;
|
||||
private: static const int PENALTY_N3;
|
||||
private: static const int PENALTY_N4;
|
||||
|
||||
|
||||
private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
|
||||
private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*---- Public exception class ----*/
|
||||
|
||||
/*
|
||||
* Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
|
||||
* - Decrease the error correction level if it was greater than Ecc::LOW.
|
||||
* - If the encodeSegments() function was called with a maxVersion argument, then increase
|
||||
* it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other
|
||||
* factory functions because they search all versions up to QrCode::MAX_VERSION.)
|
||||
* - Split the text data into better or optimal segments in order to reduce the number of bits required.
|
||||
* - Change the text or binary data to be shorter.
|
||||
* - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
|
||||
* - Propagate the error upward to the caller/user.
|
||||
*/
|
||||
class data_too_long : public std::length_error {
|
||||
|
||||
public: explicit data_too_long(const std::string &msg);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
|
||||
*/
|
||||
class BitBuffer final : public std::vector<bool> {
|
||||
|
||||
/*---- Constructor ----*/
|
||||
|
||||
// Creates an empty bit buffer (length 0).
|
||||
public: BitBuffer();
|
||||
|
||||
|
||||
|
||||
/*---- Method ----*/
|
||||
|
||||
// Appends the given number of low-order bits of the given value
|
||||
// to this buffer. Requires 0 <= len <= 31 and val < 2^len.
|
||||
public: void appendBits(std::uint32_t val, int len);
|
||||
|
||||
};
|
||||
|
||||
std::string toSvgString(const QrCode &qr, int border);
|
||||
|
||||
}
|
5
client/3rd/qrcodegen/qrcodegen.pri
Normal file
5
client/3rd/qrcodegen/qrcodegen.pri
Normal file
|
@ -0,0 +1,5 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
|
||||
HEADERS += $$PWD/qrcodegen.hpp
|
||||
SOURCES += $$PWD/qrcodegen.cpp
|
1
client/3rd/qtkeychain
Submodule
1
client/3rd/qtkeychain
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit f197cdb935b0cfd9881fdc6860874cb8379d1238
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 2fd4dd60c04a29c6d1271fdd9ae25378b8f61ec8
|
220
client/amnezia_application.cpp
Normal file
220
client/amnezia_application.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
#include "amnezia_application.h"
|
||||
|
||||
#include <QFontDatabase>
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
|
||||
|
||||
#include "core/servercontroller.h"
|
||||
#include "debug.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include "platforms/ios/QRCodeReaderBase.h"
|
||||
|
||||
#include "ui/pages.h"
|
||||
|
||||
#include "ui/pages_logic/AppSettingsLogic.h"
|
||||
#include "ui/pages_logic/GeneralSettingsLogic.h"
|
||||
#include "ui/pages_logic/NetworkSettingsLogic.h"
|
||||
#include "ui/pages_logic/NewServerProtocolsLogic.h"
|
||||
#include "ui/pages_logic/QrDecoderLogic.h"
|
||||
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
|
||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
||||
#include "ui/pages_logic/ServerListLogic.h"
|
||||
#include "ui/pages_logic/ServerSettingsLogic.h"
|
||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
||||
#include "ui/pages_logic/ShareConnectionLogic.h"
|
||||
#include "ui/pages_logic/SitesLogic.h"
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
#include "ui/pages_logic/VpnLogic.h"
|
||||
#include "ui/pages_logic/WizardLogic.h"
|
||||
|
||||
#include "ui/pages_logic/protocols/CloakLogic.h"
|
||||
#include "ui/pages_logic/protocols/OpenVpnLogic.h"
|
||||
#include "ui/pages_logic/protocols/ShadowSocksLogic.h"
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]):
|
||||
AMNEZIA_BASE_CLASS(argc, argv)
|
||||
#else
|
||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary,
|
||||
SingleApplication::Options options, int timeout, const QString &userData):
|
||||
SingleApplication(argc, argv, allowSecondary, options, timeout, userData)
|
||||
#endif
|
||||
{
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
// Fix config file permissions
|
||||
#ifdef Q_OS_LINUX
|
||||
{
|
||||
QSettings s(ORGANIZATION_NAME, APPLICATION_NAME);
|
||||
s.setValue("permFixed", true);
|
||||
}
|
||||
|
||||
QString configLoc1 = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first() + "/"
|
||||
+ ORGANIZATION_NAME + "/" + APPLICATION_NAME + ".conf";
|
||||
QFile::setPermissions(configLoc1, QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||
|
||||
QString configLoc2 = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first() + "/"
|
||||
+ ORGANIZATION_NAME + "/" + APPLICATION_NAME + "/" + APPLICATION_NAME + ".conf";
|
||||
QFile::setPermissions(configLoc2, QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||
|
||||
#endif
|
||||
|
||||
m_settings = std::shared_ptr<Settings>(new Settings);
|
||||
m_serverController = std::shared_ptr<ServerController>(new ServerController(m_settings, this));
|
||||
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, m_serverController, this));
|
||||
}
|
||||
|
||||
AmneziaApplication::~AmneziaApplication()
|
||||
{
|
||||
if (m_engine) {
|
||||
QObject::disconnect(m_engine, 0,0,0);
|
||||
delete m_engine;
|
||||
}
|
||||
if (m_uiLogic) {
|
||||
QObject::disconnect(m_uiLogic, 0,0,0);
|
||||
delete m_uiLogic;
|
||||
}
|
||||
|
||||
if (m_protocolProps) delete m_protocolProps;
|
||||
if (m_containerProps) delete m_containerProps;
|
||||
}
|
||||
|
||||
void AmneziaApplication::init()
|
||||
{
|
||||
m_engine = new QQmlApplicationEngine;
|
||||
m_uiLogic = new UiLogic(m_settings, m_configurator, m_serverController);
|
||||
|
||||
const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
|
||||
QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated,
|
||||
this, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
m_engine->rootContext()->setContextProperty("Debug", &Debug::Instance());
|
||||
m_uiLogic->registerPagesLogic();
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
setStartPageLogic(m_uiLogic->pageLogic<StartPageLogic>());
|
||||
#endif
|
||||
|
||||
m_engine->load(url);
|
||||
|
||||
if (m_engine->rootObjects().size() > 0) {
|
||||
m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0));
|
||||
}
|
||||
|
||||
if (m_settings->isSaveLogs()) {
|
||||
if (!Debug::init()) {
|
||||
qWarning() << "Initialization of debug subsystem failed";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_parser.isSet("a")) m_uiLogic->showOnStartup();
|
||||
else emit m_uiLogic->show();
|
||||
#else
|
||||
m_uiLogic->showOnStartup();
|
||||
#endif
|
||||
|
||||
// TODO - fix
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (isPrimary()) {
|
||||
QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){
|
||||
qDebug() << "Secondary instance started, showing this window instead";
|
||||
emit m_uiLogic->show();
|
||||
emit m_uiLogic->raise();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void AmneziaApplication::registerTypes()
|
||||
{
|
||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
|
||||
qRegisterMetaType<ServerCredentials>("ServerCredentials");
|
||||
|
||||
qRegisterMetaType<DockerContainer>("DockerContainer");
|
||||
qRegisterMetaType<TransportProto>("TransportProto");
|
||||
qRegisterMetaType<Proto>("Proto");
|
||||
qRegisterMetaType<ServiceType>("ServiceType");
|
||||
qRegisterMetaType<Page>("Page");
|
||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("ConnectionState");
|
||||
|
||||
qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *");
|
||||
|
||||
|
||||
declareQmlPageEnum();
|
||||
declareQmlProtocolEnum();
|
||||
declareQmlContainerEnum();
|
||||
|
||||
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
|
||||
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
|
||||
|
||||
m_containerProps = new ContainerProps;
|
||||
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps);
|
||||
|
||||
m_protocolProps = new ProtocolProps;
|
||||
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps);
|
||||
}
|
||||
|
||||
void AmneziaApplication::loadFonts()
|
||||
{
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf");
|
||||
}
|
||||
|
||||
void AmneziaApplication::loadTranslator()
|
||||
{
|
||||
m_translator = new QTranslator;
|
||||
if (m_translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) {
|
||||
installTranslator(m_translator);
|
||||
}
|
||||
}
|
||||
|
||||
bool AmneziaApplication::parseCommands()
|
||||
{
|
||||
m_parser.setApplicationDescription(APPLICATION_NAME);
|
||||
m_parser.addHelpOption();
|
||||
m_parser.addVersionOption();
|
||||
|
||||
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
|
||||
m_parser.addOption(c_autostart);
|
||||
|
||||
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
|
||||
m_parser.addOption(c_cleanup);
|
||||
|
||||
m_parser.process(*this);
|
||||
|
||||
if (m_parser.isSet(c_cleanup)) {
|
||||
Debug::cleanUp();
|
||||
QTimer::singleShot(100, this, [this]{
|
||||
quit();
|
||||
});
|
||||
exec();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||
{
|
||||
return m_engine;
|
||||
}
|
||||
|
62
client/amnezia_application.h
Normal file
62
client/amnezia_application.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef AMNEZIA_APPLICATION_H
|
||||
#define AMNEZIA_APPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include "ui/uilogic.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
|
||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#define AMNEZIA_BASE_CLASS QApplication
|
||||
#else
|
||||
#define AMNEZIA_BASE_CLASS SingleApplication
|
||||
#define QAPPLICATION_CLASS QApplication
|
||||
#include "singleapplication.h"
|
||||
#endif
|
||||
|
||||
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
AmneziaApplication(int &argc, char *argv[]);
|
||||
#else
|
||||
AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
|
||||
SingleApplication::Options options = SingleApplication::User, int timeout = 1000, const QString &userData = {} );
|
||||
#endif
|
||||
virtual ~AmneziaApplication();
|
||||
|
||||
void init();
|
||||
void registerTypes();
|
||||
void loadFonts();
|
||||
void loadTranslator();
|
||||
bool parseCommands();
|
||||
|
||||
QQmlApplicationEngine *qmlEngine() const;
|
||||
|
||||
private:
|
||||
QQmlApplicationEngine *m_engine {};
|
||||
UiLogic *m_uiLogic {};
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||
std::shared_ptr<ServerController> m_serverController;
|
||||
|
||||
ContainerProps* m_containerProps {};
|
||||
ProtocolProps* m_protocolProps {};
|
||||
|
||||
QTranslator* m_translator;
|
||||
QCommandLineParser m_parser;
|
||||
|
||||
};
|
||||
|
||||
#endif // AMNEZIA_APPLICATION_H
|
|
@ -19,7 +19,7 @@
|
|||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
|
||||
<application android:name=".qt.AmneziaApp" android:hardwareAccelerated="true" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name=".qt.VPNActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/splashScreenTheme">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name=".qt.VPNActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleInstance" android:taskAffinity="" android:theme="@style/splashScreenTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
|
24
client/android/src/org/amnezia/vpn/AuthHelper.java
Normal file
24
client/android/src/org/amnezia/vpn/AuthHelper.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package org.amnezia.vpn;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Intent;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
|
||||
import static android.content.Context.KEYGUARD_SERVICE;
|
||||
|
||||
public class AuthHelper extends QtActivity {
|
||||
|
||||
static final String TAG = "AuthHelper";
|
||||
|
||||
public static Intent getAuthIntent(Context context) {
|
||||
KeyguardManager mKeyguardManager = (KeyguardManager)context.getSystemService(KEYGUARD_SERVICE);
|
||||
if (mKeyguardManager.isDeviceSecure()) {
|
||||
return mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,29 +3,34 @@ equals(QT_MAJOR_VERSION, 6): QT += core5compat
|
|||
|
||||
TARGET = AmneziaVPN
|
||||
TEMPLATE = app
|
||||
#CONFIG += console
|
||||
|
||||
# silent builds on CI env
|
||||
IS_CI=$$(CI)
|
||||
!isEmpty(IS_CI){
|
||||
message("Detected CI env")
|
||||
CONFIG += silent ccache
|
||||
}
|
||||
|
||||
CONFIG += qtquickcompiler
|
||||
CONFIG += qzxing_multimedia \
|
||||
enable_decoder_qr_code \
|
||||
enable_encoder_qr_code
|
||||
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
include("3rd/QtSsh/src/ssh/qssh.pri")
|
||||
include("3rd/QtSsh/src/botan/botan.pri")
|
||||
!android:!ios:include("3rd/SingleApplication/singleapplication.pri")
|
||||
include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri")
|
||||
|
||||
win32-msvc*: DEFINES += __STDC_CONSTANT_MACROS
|
||||
include("3rd/qzxing/src/QZXing-components.pri")
|
||||
include("3rd/qrcodegen/qrcodegen.pri")
|
||||
include("3rd/QSimpleCrypto/QSimpleCrypto.pri")
|
||||
include("3rd/qtkeychain/qtkeychain.pri")
|
||||
|
||||
INCLUDEPATH += $$PWD/3rd/QSimpleCrypto/include
|
||||
INCLUDEPATH += $$PWD/3rd/OpenSSL/include
|
||||
DEPENDPATH += $$PWD/3rd/OpenSSL/include
|
||||
|
||||
HEADERS += \
|
||||
../ipc/ipc.h \
|
||||
amnezia_application.h \
|
||||
configurators/cloak_configurator.h \
|
||||
configurators/configurator_base.h \
|
||||
configurators/ikev2_configurator.h \
|
||||
configurators/shadowsocks_configurator.h \
|
||||
configurators/ssh_configurator.h \
|
||||
|
@ -44,6 +49,7 @@ HEADERS += \
|
|||
platforms/ios/MobileUtils.h \
|
||||
platforms/linux/leakdetector.h \
|
||||
protocols/protocols_defs.h \
|
||||
secure_qsettings.h \
|
||||
settings.h \
|
||||
ui/notificationhandler.h \
|
||||
ui/models/containers_model.h \
|
||||
|
@ -62,6 +68,7 @@ HEADERS += \
|
|||
ui/pages_logic/ShareConnectionLogic.h \
|
||||
ui/pages_logic/SitesLogic.h \
|
||||
ui/pages_logic/StartPageLogic.h \
|
||||
ui/pages_logic/ViewConfigLogic.h \
|
||||
ui/pages_logic/VpnLogic.h \
|
||||
ui/pages_logic/WizardLogic.h \
|
||||
ui/pages_logic/protocols/CloakLogic.h \
|
||||
|
@ -84,7 +91,9 @@ HEADERS += \
|
|||
platforms/ios/QRCodeReaderBase.h
|
||||
|
||||
SOURCES += \
|
||||
amnezia_application.cpp \
|
||||
configurators/cloak_configurator.cpp \
|
||||
configurators/configurator_base.cpp \
|
||||
configurators/ikev2_configurator.cpp \
|
||||
configurators/shadowsocks_configurator.cpp \
|
||||
configurators/ssh_configurator.cpp \
|
||||
|
@ -102,6 +111,7 @@ SOURCES += \
|
|||
platforms/ios/MobileUtils.cpp \
|
||||
platforms/linux/leakdetector.cpp \
|
||||
protocols/protocols_defs.cpp \
|
||||
secure_qsettings.cpp \
|
||||
settings.cpp \
|
||||
ui/notificationhandler.cpp \
|
||||
ui/models/containers_model.cpp \
|
||||
|
@ -119,6 +129,7 @@ SOURCES += \
|
|||
ui/pages_logic/ShareConnectionLogic.cpp \
|
||||
ui/pages_logic/SitesLogic.cpp \
|
||||
ui/pages_logic/StartPageLogic.cpp \
|
||||
ui/pages_logic/ViewConfigLogic.cpp \
|
||||
ui/pages_logic/VpnLogic.cpp \
|
||||
ui/pages_logic/WizardLogic.cpp \
|
||||
ui/pages_logic/protocols/CloakLogic.cpp \
|
||||
|
@ -168,7 +179,6 @@ win32 {
|
|||
-lshlwapi \
|
||||
-liphlpapi \
|
||||
-lws2_32 \
|
||||
-liphlpapi \
|
||||
-lgdi32
|
||||
|
||||
QMAKE_LFLAGS_WINDOWS += /entry:mainCRTStartup
|
||||
|
@ -248,13 +258,11 @@ android {
|
|||
INCLUDEPATH += platforms/android
|
||||
|
||||
HEADERS += \
|
||||
platforms/android/native.h \
|
||||
platforms/android/android_controller.h \
|
||||
platforms/android/android_notificationhandler.h \
|
||||
protocols/android_vpnprotocol.h
|
||||
|
||||
SOURCES += \
|
||||
platforms/android/native.cpp \
|
||||
platforms/android/android_controller.cpp \
|
||||
platforms/android/android_notificationhandler.cpp \
|
||||
protocols/android_vpnprotocol.cpp
|
||||
|
@ -295,7 +303,7 @@ android {
|
|||
}
|
||||
|
||||
ios {
|
||||
message("Client ios build")
|
||||
message("Client iOS build")
|
||||
CONFIG += static
|
||||
CONFIG += file_copies
|
||||
|
||||
|
@ -322,7 +330,7 @@ ios {
|
|||
platforms/ios/QtAppDelegate-C-Interface.h
|
||||
|
||||
SOURCES -= \
|
||||
platforms/ios/QRCodeReader.cpp \
|
||||
platforms/ios/QRCodeReaderBase.cpp \
|
||||
platforms/ios/MobileUtils.cpp
|
||||
|
||||
SOURCES += \
|
||||
|
|
|
@ -4,18 +4,25 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "core/servercontroller.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
CloakConfigurator::CloakConfigurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
{
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
QString cloakPublicKey = ServerController::getTextFileFromContainer(container, credentials,
|
||||
QString cloakPublicKey = m_serverController->getTextFileFromContainer(container, credentials,
|
||||
amnezia::protocols::cloak::ckPublicKeyPath, &e);
|
||||
cloakPublicKey.replace("\n", "");
|
||||
|
||||
QString cloakBypassUid = ServerController::getTextFileFromContainer(container, credentials,
|
||||
QString cloakBypassUid = m_serverController->getTextFileFromContainer(container, credentials,
|
||||
amnezia::protocols::cloak::ckBypassUidKeyPath, &e);
|
||||
cloakBypassUid.replace("\n", "");
|
||||
|
||||
|
@ -40,8 +47,8 @@ QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
|
|||
config.insert(config_key::remote, credentials.hostName);
|
||||
config.insert(config_key::port, "$CLOAK_SERVER_PORT");
|
||||
|
||||
QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(),
|
||||
ServerController::genVarsForScript(credentials, container, containerConfig));
|
||||
QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(),
|
||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
// qDebug().noquote() << textCfg;
|
||||
return textCfg;
|
||||
|
|
|
@ -3,15 +3,18 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "configurator_base.h"
|
||||
|
||||
class CloakConfigurator
|
||||
using namespace amnezia;
|
||||
|
||||
class CloakConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CloakConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
static QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
};
|
||||
|
||||
|
|
10
client/configurators/configurator_base.cpp
Normal file
10
client/configurators/configurator_base.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "configurator_base.h"
|
||||
|
||||
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent)
|
||||
: QObject{parent},
|
||||
m_settings(settings),
|
||||
m_serverController(serverController)
|
||||
{
|
||||
|
||||
}
|
25
client/configurators/configurator_base.h
Normal file
25
client/configurators/configurator_base.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef CONFIGURATORBASE_H
|
||||
#define CONFIGURATORBASE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Settings;
|
||||
class ServerController;
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/defs.h"
|
||||
|
||||
class ConfiguratorBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConfiguratorBase(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<ServerController> m_serverController;
|
||||
|
||||
};
|
||||
|
||||
#endif // CONFIGURATORBASE_H
|
|
@ -8,12 +8,18 @@
|
|||
#include <QJsonDocument>
|
||||
#include <QUuid>
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
#include "core/server_defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/server_defs.h"
|
||||
#include "core/scripts_registry.h"
|
||||
#include "utilities.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
|
||||
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode)
|
||||
|
@ -35,16 +41,16 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
|
|||
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
|
||||
.arg(connData.clientId);
|
||||
|
||||
ErrorCode e = ServerController::runContainerScript(credentials, container, scriptCreateCert);
|
||||
ErrorCode e = m_serverController->runContainerScript(credentials, container, scriptCreateCert);
|
||||
|
||||
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
|
||||
.arg(connData.password)
|
||||
.arg(connData.clientId)
|
||||
.arg(certFileName);
|
||||
e = ServerController::runContainerScript(credentials, container, scriptExportCert);
|
||||
e = m_serverController->runContainerScript(credentials, container, scriptExportCert);
|
||||
|
||||
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e);
|
||||
connData.caCert = ServerController::getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
|
||||
connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials, certFileName, &e);
|
||||
connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
|
||||
|
||||
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
|
||||
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class Ikev2Configurator
|
||||
class Ikev2Configurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Ikev2Configurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
struct ConnectionData {
|
||||
QByteArray clientCert; // p12 client cert
|
||||
|
@ -19,14 +22,14 @@ public:
|
|||
QString host; // host ip
|
||||
};
|
||||
|
||||
static QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QString genIkev2Config(const ConnectionData &connData);
|
||||
static QString genMobileConfig(const ConnectionData &connData);
|
||||
static QString genStrongSwanConfig(const ConnectionData &connData);
|
||||
QString genIkev2Config(const ConnectionData &connData);
|
||||
QString genMobileConfig(const ConnectionData &connData);
|
||||
QString genStrongSwanConfig(const ConnectionData &connData);
|
||||
|
||||
static ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
|
||||
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode = nullptr);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,16 +6,25 @@
|
|||
#include <QDebug>
|
||||
#include <QTemporaryFile>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "core/server_defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/server_defs.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "core/scripts_registry.h"
|
||||
#include "utilities.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode)
|
||||
{
|
||||
|
@ -31,7 +40,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
arg(amnezia::protocols::openvpn::clientsDirPath).
|
||||
arg(connData.clientId);
|
||||
|
||||
ErrorCode e = ServerController::uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
|
||||
ErrorCode e = m_serverController->uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
|
||||
if (e) {
|
||||
if (errorCode) *errorCode = e;
|
||||
return connData;
|
||||
|
@ -43,8 +52,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
return connData;
|
||||
}
|
||||
|
||||
connData.caCert = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e);
|
||||
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials,
|
||||
connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e);
|
||||
connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials,
|
||||
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e);
|
||||
|
||||
if (e) {
|
||||
|
@ -52,7 +61,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
return connData;
|
||||
}
|
||||
|
||||
connData.taKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e);
|
||||
connData.taKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e);
|
||||
|
||||
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
|
||||
if (errorCode) *errorCode = ErrorCode::RemoteProcessCrashError;
|
||||
|
@ -61,17 +70,11 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
return connData;
|
||||
}
|
||||
|
||||
Settings &OpenVpnConfigurator::m_settings()
|
||||
{
|
||||
static Settings s;
|
||||
return s;
|
||||
}
|
||||
|
||||
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
{
|
||||
QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
|
||||
ServerController::genVarsForScript(credentials, container, containerConfig));
|
||||
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
|
||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
|
||||
if (errorCode && *errorCode) {
|
||||
|
@ -105,7 +108,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
|
|||
QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object();
|
||||
QString config = json[config_key::config].toString();
|
||||
|
||||
if (m_settings().routeMode() != Settings::VpnAllSites) {
|
||||
if (m_settings->routeMode() != Settings::VpnAllSites) {
|
||||
config.replace("redirect-gateway def1 bypass-dhcp", "");
|
||||
}
|
||||
else {
|
||||
|
@ -161,9 +164,9 @@ ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
|
|||
.arg(clientId);
|
||||
|
||||
QStringList scriptList {script_import, script_sign};
|
||||
QString script = ServerController::replaceVars(scriptList.join("\n"), ServerController::genVarsForScript(credentials, container));
|
||||
QString script = m_serverController->replaceVars(scriptList.join("\n"), m_serverController->genVarsForScript(credentials, container));
|
||||
|
||||
return ServerController::runScript(credentials, script);
|
||||
return m_serverController->runScript(credentials, script);
|
||||
}
|
||||
|
||||
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class OpenVpnConfigurator
|
||||
class OpenVpnConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenVpnConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
struct ConnectionData {
|
||||
QString clientId;
|
||||
|
@ -22,22 +24,21 @@ public:
|
|||
QString host; // host ip
|
||||
};
|
||||
|
||||
static QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QString processConfigWithLocalSettings(QString jsonConfig);
|
||||
static QString processConfigWithExportSettings(QString jsonConfig);
|
||||
QString processConfigWithLocalSettings(QString jsonConfig);
|
||||
QString processConfigWithExportSettings(QString jsonConfig);
|
||||
|
||||
static ErrorCode signCert(DockerContainer container,
|
||||
ErrorCode signCert(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString clientId);
|
||||
|
||||
private:
|
||||
static ConnectionData createCertRequest();
|
||||
ConnectionData createCertRequest();
|
||||
|
||||
static ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials,
|
||||
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static Settings &m_settings();
|
||||
};
|
||||
|
||||
#endif // OPENVPN_CONFIGURATOR_H
|
||||
|
|
|
@ -5,13 +5,20 @@
|
|||
#include <QJsonDocument>
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
{
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
QString ssKey = ServerController::getTextFileFromContainer(container, credentials,
|
||||
QString ssKey = m_serverController->getTextFileFromContainer(container, credentials,
|
||||
amnezia::protocols::shadowsocks::ssKeyPath, &e);
|
||||
ssKey.replace("\n", "");
|
||||
|
||||
|
@ -29,8 +36,8 @@ QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &c
|
|||
config.insert("method", "$SHADOWSOCKS_CIPHER");
|
||||
|
||||
|
||||
QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(),
|
||||
ServerController::genVarsForScript(credentials, container, containerConfig));
|
||||
QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(),
|
||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
//qDebug().noquote() << textCfg;
|
||||
return textCfg;
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class ShadowSocksConfigurator
|
||||
class ShadowSocksConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ShadowSocksConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
static QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,15 @@
|
|||
#include "core/server_defs.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||
{
|
||||
|
|
|
@ -4,16 +4,19 @@
|
|||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class SshConfigurator
|
||||
class SshConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QProcessEnvironment prepareEnv();
|
||||
static QString convertOpenSShKey(const QString &key);
|
||||
static void openSshTerminal(const ServerCredentials &credentials);
|
||||
SshConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
QProcessEnvironment prepareEnv();
|
||||
QString convertOpenSShKey(const QString &key);
|
||||
void openSshTerminal(const ServerCredentials &credentials);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "shadowsocks_configurator.h"
|
||||
#include "wireguard_configurator.h"
|
||||
#include "ikev2_configurator.h"
|
||||
#include "ssh_configurator.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
|
@ -11,11 +12,18 @@
|
|||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "utilities.h"
|
||||
#include "settings.h"
|
||||
|
||||
Settings &VpnConfigurator::m_settings()
|
||||
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
static Settings s;
|
||||
return s;
|
||||
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, serverController, this));
|
||||
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, serverController, this));
|
||||
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, serverController, this));
|
||||
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, serverController, this));
|
||||
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, serverController, this));
|
||||
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, serverController, this));
|
||||
}
|
||||
|
||||
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
|
||||
|
@ -23,19 +31,19 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
|
|||
{
|
||||
switch (proto) {
|
||||
case Proto::OpenVpn:
|
||||
return OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, errorCode);
|
||||
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode);
|
||||
|
||||
case Proto::ShadowSocks:
|
||||
return ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, errorCode);
|
||||
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
|
||||
|
||||
case Proto::Cloak:
|
||||
return CloakConfigurator::genCloakConfig(credentials, container, containerConfig, errorCode);
|
||||
return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
|
||||
|
||||
case Proto::WireGuard:
|
||||
return WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
|
||||
case Proto::Ikev2:
|
||||
return Ikev2Configurator::genIkev2Config(credentials, container, containerConfig, errorCode);
|
||||
return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
|
||||
|
||||
default:
|
||||
return "";
|
||||
|
@ -46,20 +54,20 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
|
|||
{
|
||||
QPair<QString, QString> dns;
|
||||
|
||||
bool useAmneziaDns = m_settings().useAmneziaDns();
|
||||
const QJsonObject &server = m_settings().server(serverIndex);
|
||||
bool useAmneziaDns = m_settings->useAmneziaDns();
|
||||
const QJsonObject &server = m_settings->server(serverIndex);
|
||||
|
||||
dns.first = server.value(config_key::dns1).toString();
|
||||
dns.second = server.value(config_key::dns2).toString();
|
||||
|
||||
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
|
||||
if (useAmneziaDns && m_settings().containers(serverIndex).contains(DockerContainer::Dns)) {
|
||||
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
|
||||
dns.first = protocols::dns::amneziaDnsIp;
|
||||
}
|
||||
else dns.first = m_settings().primaryDns();
|
||||
else dns.first = m_settings->primaryDns();
|
||||
}
|
||||
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
|
||||
dns.second = m_settings().secondaryDns();
|
||||
dns.second = m_settings->secondaryDns();
|
||||
}
|
||||
|
||||
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
|
||||
|
@ -83,7 +91,7 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker
|
|||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
config = OpenVpnConfigurator::processConfigWithLocalSettings(config);
|
||||
config = openVpnConfigurator->processConfigWithLocalSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
@ -94,7 +102,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke
|
|||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
config = OpenVpnConfigurator::processConfigWithExportSettings(config);
|
||||
config = openVpnConfigurator->processConfigWithExportSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -3,29 +3,46 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
|
||||
class OpenVpnConfigurator;
|
||||
class ShadowSocksConfigurator;
|
||||
class CloakConfigurator;
|
||||
class WireguardConfigurator;
|
||||
class Ikev2Configurator;
|
||||
class SshConfigurator;
|
||||
|
||||
// Retrieve connection settings from server
|
||||
class VpnConfigurator
|
||||
class VpnConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VpnConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QPair<QString, QString> getDnsForConfig(int serverIndex);
|
||||
static QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
QPair<QString, QString> getDnsForConfig(int serverIndex);
|
||||
QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
static QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
static QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
// workaround for containers which is not support normal configaration
|
||||
static void updateContainerConfigAfterInstallation(DockerContainer container,
|
||||
void updateContainerConfigAfterInstallation(DockerContainer container,
|
||||
QJsonObject &containerConfig, const QString &stdOut);
|
||||
|
||||
static Settings &m_settings();
|
||||
std::shared_ptr<ServerController> m_serverController;
|
||||
|
||||
std::shared_ptr<OpenVpnConfigurator> openVpnConfigurator;
|
||||
std::shared_ptr<ShadowSocksConfigurator> shadowSocksConfigurator;
|
||||
std::shared_ptr<CloakConfigurator> cloakConfigurator;
|
||||
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
|
||||
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
|
||||
std::shared_ptr<SshConfigurator> sshConfigurator;
|
||||
};
|
||||
|
||||
#endif // VPN_CONFIGURATOR_H
|
||||
|
|
|
@ -5,18 +5,27 @@
|
|||
#include <QTemporaryDir>
|
||||
#include <QDebug>
|
||||
#include <QTemporaryFile>
|
||||
#include <QJsonDocument>
|
||||
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
#include "core/server_defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/server_defs.h"
|
||||
#include "core/scripts_registry.h"
|
||||
#include "utilities.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "settings.h"
|
||||
|
||||
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, std::shared_ptr<ServerController> serverController, QObject *parent):
|
||||
ConfiguratorBase(settings, serverController, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
||||
{
|
||||
|
@ -71,7 +80,12 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
|||
stdOut += data + "\n";
|
||||
};
|
||||
|
||||
ServerController::runContainerScript(credentials, container, script, cbReadStdOut);
|
||||
e = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut);
|
||||
if (errorCode && e) {
|
||||
*errorCode = e;
|
||||
return connData;
|
||||
}
|
||||
|
||||
stdOut.replace("AllowedIPs = ", "");
|
||||
stdOut.replace("/32", "");
|
||||
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
|
||||
|
@ -104,14 +118,14 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
|||
}
|
||||
|
||||
// Get keys
|
||||
connData.serverPubKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
|
||||
connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
|
||||
connData.serverPubKey.replace("\n", "");
|
||||
if (e) {
|
||||
if (errorCode) *errorCode = e;
|
||||
return connData;
|
||||
}
|
||||
|
||||
connData.pskKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e);
|
||||
connData.pskKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e);
|
||||
connData.pskKey.replace("\n", "");
|
||||
|
||||
if (e) {
|
||||
|
@ -129,7 +143,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
|||
arg(connData.pskKey).
|
||||
arg(connData.clientIP);
|
||||
|
||||
e = ServerController::uploadTextFileToContainer(container, credentials, configPart,
|
||||
e = m_serverController->uploadTextFileToContainer(container, credentials, configPart,
|
||||
protocols::wireguard::serverConfigPath, QSsh::SftpOverwriteMode::SftpAppendToExisting);
|
||||
|
||||
if (e) {
|
||||
|
@ -137,24 +151,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
|||
return connData;
|
||||
}
|
||||
|
||||
e = ServerController::runScript(credentials,
|
||||
ServerController::replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'",
|
||||
ServerController::genVarsForScript(credentials, container)));
|
||||
e = m_serverController->runScript(credentials,
|
||||
m_serverController->replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'",
|
||||
m_serverController->genVarsForScript(credentials, container)));
|
||||
|
||||
return connData;
|
||||
}
|
||||
|
||||
Settings &WireguardConfigurator::m_settings()
|
||||
{
|
||||
static Settings s;
|
||||
return s;
|
||||
}
|
||||
|
||||
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
{
|
||||
QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
|
||||
ServerController::genVarsForScript(credentials, container, containerConfig));
|
||||
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
|
||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
if (errorCode && *errorCode) {
|
||||
|
@ -182,8 +190,8 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
|
|||
QString WireguardConfigurator::processConfigWithLocalSettings(QString config)
|
||||
{
|
||||
// TODO replace DNS if it already set
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
config.replace("$PRIMARY_DNS", m_settings->primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
|
||||
|
||||
QJsonObject jConfig;
|
||||
jConfig[config_key::config] = config;
|
||||
|
@ -193,8 +201,8 @@ QString WireguardConfigurator::processConfigWithLocalSettings(QString config)
|
|||
|
||||
QString WireguardConfigurator::processConfigWithExportSettings(QString config)
|
||||
{
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
config.replace("$PRIMARY_DNS", m_settings->primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
|
||||
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class WireguardConfigurator
|
||||
class WireguardConfigurator : ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WireguardConfigurator(std::shared_ptr<Settings> settings,
|
||||
std::shared_ptr<ServerController> serverController, QObject *parent = nullptr);
|
||||
|
||||
struct ConnectionData {
|
||||
QString clientPrivKey; // client private key
|
||||
|
@ -21,20 +23,18 @@ public:
|
|||
QString host; // host ip
|
||||
};
|
||||
|
||||
static QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QString processConfigWithLocalSettings(QString config);
|
||||
static QString processConfigWithExportSettings(QString config);
|
||||
QString processConfigWithLocalSettings(QString config);
|
||||
QString processConfigWithExportSettings(QString config);
|
||||
|
||||
|
||||
private:
|
||||
static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
|
||||
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static ConnectionData genClientKeys();
|
||||
|
||||
static Settings &m_settings();
|
||||
ConnectionData genClientKeys();
|
||||
};
|
||||
|
||||
#endif // WIREGUARD_CONFIGURATOR_H
|
||||
|
|
|
@ -18,18 +18,18 @@
|
|||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "server_defs.h"
|
||||
#include "settings.h"
|
||||
#include "scripts_registry.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <configurators/vpn_configurator.h>
|
||||
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
Settings &ServerController::m_settings()
|
||||
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) :
|
||||
m_settings(settings)
|
||||
{
|
||||
static Settings s;
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
|
||||
|
@ -605,7 +605,7 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
|
|||
cbReadStdOut, cbReadStdErr);
|
||||
|
||||
|
||||
VpnConfigurator::updateContainerConfigAfterInstallation(container, config, stdOut);
|
||||
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
@ -698,8 +698,8 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
|||
|
||||
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
|
||||
|
||||
vars.append({{"$PRIMARY_SERVER_DNS", m_settings().primaryDns()}});
|
||||
vars.append({{"$SECONDARY_SERVER_DNS", m_settings().secondaryDns()}});
|
||||
vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}});
|
||||
vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}});
|
||||
|
||||
|
||||
// Sftp vars
|
||||
|
|
|
@ -7,78 +7,83 @@
|
|||
#include "sshremoteprocess.h"
|
||||
#include "debug.h"
|
||||
#include "defs.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
class Settings;
|
||||
class VpnConfigurator;
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
class ServerController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServerController(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
typedef QList<QPair<QString, QString>> Vars;
|
||||
|
||||
static ErrorCode fromSshConnectionErrorCode(QSsh::SshError error);
|
||||
ErrorCode fromSshConnectionErrorCode(QSsh::SshError error);
|
||||
|
||||
// QSsh exitCode and exitStatus are different things
|
||||
static ErrorCode fromSshProcessExitStatus(int exitStatus);
|
||||
ErrorCode fromSshProcessExitStatus(int exitStatus);
|
||||
|
||||
static QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials);
|
||||
static void disconnectFromHost(const ServerCredentials &credentials);
|
||||
QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials);
|
||||
void disconnectFromHost(const ServerCredentials &credentials);
|
||||
|
||||
static ErrorCode removeAllContainers(const ServerCredentials &credentials);
|
||||
static ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
|
||||
static ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
static ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||
ErrorCode removeAllContainers(const ServerCredentials &credentials);
|
||||
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &oldConfig, QJsonObject &newConfig);
|
||||
|
||||
// create initial config - generate passwords, etc
|
||||
static QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
|
||||
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
|
||||
|
||||
static bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
||||
bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
||||
|
||||
static ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials);
|
||||
ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials);
|
||||
|
||||
static ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||
const QString &remotePath, QSsh::SftpOverwriteMode overwriteMode = QSsh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
static ErrorCode uploadTextFileToContainer(DockerContainer container,
|
||||
ErrorCode uploadTextFileToContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &file, const QString &path,
|
||||
QSsh::SftpOverwriteMode overwriteMode = QSsh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
static QByteArray getTextFileFromContainer(DockerContainer container,
|
||||
QByteArray getTextFileFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
|
||||
static QString replaceVars(const QString &script, const Vars &vars);
|
||||
QString replaceVars(const QString &script, const Vars &vars);
|
||||
|
||||
static ErrorCode runScript(const ServerCredentials &credentials, QString script,
|
||||
ErrorCode runScript(const ServerCredentials &credentials, QString script,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut = nullptr,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr = nullptr);
|
||||
|
||||
static ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut = nullptr,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr = nullptr);
|
||||
|
||||
static Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
||||
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
||||
|
||||
static QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
||||
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
|
||||
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
||||
QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
|
||||
|
||||
private:
|
||||
|
||||
static ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
||||
static ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
static ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
static ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
|
||||
static Settings &m_settings();
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||
};
|
||||
|
||||
#endif // SERVERCONTROLLER_H
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#define APPLICATION_NAME "AmneziaVPN"
|
||||
#define SERVICE_NAME "AmneziaVPN-service"
|
||||
#define ORGANIZATION_NAME "AmneziaVPN.ORG"
|
||||
#define APP_MAJOR_VERSION "2.0.10"
|
||||
#define APP_VERSION "2.0.10.0"
|
||||
#define APP_MAJOR_VERSION "2.1.2"
|
||||
#define APP_VERSION "2.1.2.0"
|
||||
|
||||
#endif // DEFINES_H
|
||||
|
|
219
client/main.cpp
219
client/main.cpp
|
@ -1,86 +1,33 @@
|
|||
#include <QApplication>
|
||||
#include <QFontDatabase>
|
||||
#include <QCommandLineParser>
|
||||
#include <QMessageBox>
|
||||
#include <QTranslator>
|
||||
#include <QTimer>
|
||||
#include <QLoggingCategory>
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include "ui/uilogic.h"
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
#include "ui/pages.h"
|
||||
|
||||
#include "ui/pages_logic/AppSettingsLogic.h"
|
||||
#include "ui/pages_logic/GeneralSettingsLogic.h"
|
||||
#include "ui/pages_logic/NetworkSettingsLogic.h"
|
||||
#include "ui/pages_logic/NewServerProtocolsLogic.h"
|
||||
#include "ui/pages_logic/QrDecoderLogic.h"
|
||||
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
|
||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
||||
#include "ui/pages_logic/ServerListLogic.h"
|
||||
#include "ui/pages_logic/ServerSettingsLogic.h"
|
||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
||||
#include "ui/pages_logic/ShareConnectionLogic.h"
|
||||
#include "ui/pages_logic/SitesLogic.h"
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
#include "ui/pages_logic/VpnLogic.h"
|
||||
#include "ui/pages_logic/WizardLogic.h"
|
||||
|
||||
#include "ui/pages_logic/protocols/CloakLogic.h"
|
||||
#include "ui/pages_logic/protocols/OpenVpnLogic.h"
|
||||
#include "ui/pages_logic/protocols/ShadowSocksLogic.h"
|
||||
|
||||
#include "ui/uilogic.h"
|
||||
|
||||
#include "QZXing.h"
|
||||
|
||||
#include "platforms/ios/QRCodeReaderBase.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "amnezia_application.h"
|
||||
#include "defines.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#define QAPPLICATION_CLASS QGuiApplication
|
||||
#include "singleapplication.h"
|
||||
#undef QAPPLICATION_CLASS
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "Windows.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include "native.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
#include "QtAppDelegate-C-Interface.h"
|
||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||
#endif
|
||||
|
||||
static void loadTranslator()
|
||||
{
|
||||
QTranslator* translator = new QTranslator;
|
||||
if (translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) {
|
||||
qApp->installTranslator(translator);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
|
||||
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
AllowSetForegroundWindow(ASFW_ANY);
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
SingleApplication app(argc, argv, true, SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification);
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
AmneziaApplication app(argc, argv);
|
||||
#else
|
||||
AmneziaApplication app(argc, argv, true, SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification);
|
||||
|
||||
if (!app.isPrimary()) {
|
||||
QTimer::singleShot(1000, &app, [&](){
|
||||
|
@ -88,163 +35,31 @@ int main(int argc, char *argv[])
|
|||
});
|
||||
return app.exec();
|
||||
}
|
||||
#else
|
||||
QApplication app(argc, argv);
|
||||
#endif
|
||||
|
||||
// Allow to raise app window if secondary instance launched
|
||||
#ifdef Q_OS_WIN
|
||||
AllowSetForegroundWindow(0);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
NativeHelpers::registerApplicationInstance(&app);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
QtAppDelegateInitialize();
|
||||
#endif
|
||||
|
||||
loadTranslator();
|
||||
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf");
|
||||
app.registerTypes();
|
||||
|
||||
app.setApplicationName(APPLICATION_NAME);
|
||||
app.setOrganizationName(ORGANIZATION_NAME);
|
||||
app.setApplicationDisplayName(APPLICATION_NAME);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(APPLICATION_NAME);
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
app.loadTranslator();
|
||||
app.loadFonts();
|
||||
|
||||
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
|
||||
parser.addOption(c_autostart);
|
||||
|
||||
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
|
||||
parser.addOption(c_cleanup);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(c_cleanup)) {
|
||||
Debug::cleanUp();
|
||||
QTimer::singleShot(100,[&app]{
|
||||
app.quit();
|
||||
});
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
|
||||
if (settings.isSaveLogs()) {
|
||||
if (!Debug::init()) {
|
||||
qWarning() << "Initialization of debug subsystem failed";
|
||||
}
|
||||
}
|
||||
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
QZXing::registerQMLTypes();
|
||||
|
||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
|
||||
qRegisterMetaType<ServerCredentials>("ServerCredentials");
|
||||
|
||||
qRegisterMetaType<DockerContainer>("DockerContainer");
|
||||
qRegisterMetaType<TransportProto>("TransportProto");
|
||||
qRegisterMetaType<Proto>("Proto");
|
||||
qRegisterMetaType<ServiceType>("ServiceType");
|
||||
qRegisterMetaType<Page>("Page");
|
||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("ConnectionState");
|
||||
|
||||
qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *");
|
||||
|
||||
UiLogic *uiLogic = new UiLogic;
|
||||
|
||||
QQmlApplicationEngine *engine = new QQmlApplicationEngine;
|
||||
|
||||
declareQmlPageEnum();
|
||||
declareQmlProtocolEnum();
|
||||
declareQmlContainerEnum();
|
||||
|
||||
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
|
||||
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
|
||||
|
||||
QScopedPointer<ContainerProps> containerProps(new ContainerProps);
|
||||
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get());
|
||||
|
||||
QScopedPointer<ProtocolProps> protocolProps(new ProtocolProps);
|
||||
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get());
|
||||
|
||||
const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
|
||||
QObject::connect(engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
engine->rootContext()->setContextProperty("Debug", &Debug::Instance());
|
||||
|
||||
engine->rootContext()->setContextProperty("UiLogic", uiLogic);
|
||||
|
||||
engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
|
||||
engine->rootContext()->setContextProperty("QrDecoderLogic", uiLogic->qrDecoderLogic());
|
||||
engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
|
||||
engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
|
||||
engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverprotocolsLogic());
|
||||
engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic());
|
||||
engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic());
|
||||
engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic());
|
||||
engine->rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic());
|
||||
engine->rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic());
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
setStartPageLogic(uiLogic->startPageLogic());
|
||||
#endif
|
||||
|
||||
engine->load(url);
|
||||
|
||||
QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){
|
||||
QObject::disconnect(engine, 0,0,0);
|
||||
delete engine;
|
||||
|
||||
QObject::disconnect(uiLogic, 0,0,0);
|
||||
delete uiLogic;
|
||||
});
|
||||
|
||||
if (engine->rootObjects().size() > 0) {
|
||||
uiLogic->setQmlRoot(engine->rootObjects().at(0));
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (parser.isSet("a")) uiLogic->showOnStartup();
|
||||
else emit uiLogic->show();
|
||||
#else
|
||||
uiLogic->showOnStartup();
|
||||
#endif
|
||||
|
||||
// TODO - fix
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (app.isPrimary()) {
|
||||
QObject::connect(&app, &SingleApplication::instanceStarted, uiLogic, [&](){
|
||||
qDebug() << "Secondary instance started, showing this window instead";
|
||||
emit uiLogic->show();
|
||||
emit uiLogic->raise();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
bool doExec = app.parseCommands();
|
||||
|
||||
if (doExec) {
|
||||
app.init();
|
||||
return app.exec();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
#include "native.h"
|
||||
#include <QMetaObject>
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <jni.h>
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
|
||||
QObject *NativeHelpers::application_p_ = 0;
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
|
||||
// define our native static functions
|
||||
// these are the functions that Java part will call directly from Android UI thread
|
||||
static void onPermissionsGranted(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsGranted"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
static void onPermissionsDenied(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsDenied"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
//create a vector with all our JNINativeMethod(s)
|
||||
static JNINativeMethod methods[] = {
|
||||
{"onPermissionsGranted", "()V", (void *)onPermissionsGranted},
|
||||
{"onPermissionsDenied", "()V", (void *)onPermissionsDenied},
|
||||
};
|
||||
|
||||
// this method is called automatically by Java after the .so file is loaded
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
|
||||
{
|
||||
JNIEnv* env;
|
||||
// get the JNIEnv pointer.
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
// search for Java class which declares the native methods
|
||||
jclass javaClass = env->FindClass("org/ftylitak/qzxing/NativeFunctions");
|
||||
if (!javaClass)
|
||||
return JNI_ERR;
|
||||
|
||||
// register our native methods
|
||||
if (env->RegisterNatives(javaClass, methods,
|
||||
sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
#endif // Q_OS_ANDROID
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef NATIVE_H
|
||||
#define NATIVE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class NativeHelpers {
|
||||
public:
|
||||
static void registerApplicationInstance(QObject *app_p) {
|
||||
application_p_ = app_p;
|
||||
}
|
||||
|
||||
static QObject* getApplicationInstance() {
|
||||
return application_p_;
|
||||
}
|
||||
|
||||
private:
|
||||
static QObject *application_p_;
|
||||
};
|
||||
|
||||
#endif // NATIVE_H
|
|
@ -1,5 +1,5 @@
|
|||
#include "MobileUtils.h"
|
||||
|
||||
void MobileUtils::shareText(const QStringList& filesToSend) {
|
||||
void MobileUtils::shareText(const QStringList&) {}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public:
|
|||
|
||||
public slots:
|
||||
static void shareText(const QStringList& filesToSend);
|
||||
|
||||
};
|
||||
|
||||
#endif // MOBILEUTILS_H
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "MobileUtils.h"
|
||||
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
static UIViewController* getViewController() {
|
||||
NSArray *windows = [[UIApplication sharedApplication]windows];
|
||||
|
@ -31,3 +34,4 @@ void MobileUtils::shareText(const QStringList& filesToSend) {
|
|||
popController.sourceView = qtController.view;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ ErrorCode Ikev2Protocol::start()
|
|||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
certInstallProcess->setProgram("certutil");
|
||||
certInstallProcess->setProgram(PermittedProcess::CertUtil);
|
||||
QStringList arguments({"-f" , "-importpfx",
|
||||
"-p", m_config[config_key::password].toString(),
|
||||
certFile.fileName(), "NoExport"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "openvpnovercloakprotocol.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
#include "utilities.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QTcpSocket>
|
||||
#include <QTcpServer>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
#include "debug.h"
|
||||
#include "defines.h"
|
||||
|
@ -122,6 +123,21 @@ void OpenVpnProtocol::sendManagementCommand(const QString& command)
|
|||
}
|
||||
}
|
||||
|
||||
uint OpenVpnProtocol::selectMgmtPort()
|
||||
{
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
quint32 port = QRandomGenerator::global()->generate();
|
||||
port = (double)(65000-15001) * port / UINT32_MAX + 15001;
|
||||
|
||||
QTcpServer s;
|
||||
bool ok = s.listen(QHostAddress::LocalHost, port);
|
||||
if (ok) return port;
|
||||
}
|
||||
|
||||
return m_managementPort;
|
||||
}
|
||||
|
||||
void OpenVpnProtocol::updateRouteGateway(QString line)
|
||||
{
|
||||
// TODO: fix for macos
|
||||
|
@ -132,24 +148,13 @@ void OpenVpnProtocol::updateRouteGateway(QString line)
|
|||
qDebug() << "Set VPN route gateway" << m_routeGateway;
|
||||
}
|
||||
|
||||
QString OpenVpnProtocol::openVpnExecPath() const
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable("openvpn/openvpn", true);
|
||||
#elif defined Q_OS_LINUX
|
||||
return Utils::usrExecutable("openvpn");
|
||||
#else
|
||||
return Utils::executable("/openvpn", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
ErrorCode OpenVpnProtocol::start()
|
||||
{
|
||||
#ifndef Q_OS_IOS
|
||||
//qDebug() << "Start OpenVPN connection";
|
||||
OpenVpnProtocol::stop();
|
||||
|
||||
if (!QFileInfo::exists(openVpnExecPath())) {
|
||||
if (!QFileInfo::exists(Utils::openVpnExecPath())) {
|
||||
setLastError(ErrorCode::OpenVpnExecutableMissing);
|
||||
return lastError();
|
||||
}
|
||||
|
@ -162,7 +167,10 @@ ErrorCode OpenVpnProtocol::start()
|
|||
// QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
|
||||
// Utils::createEmptyFile(vpnLogFileNamePath);
|
||||
|
||||
if (!m_managementServer.start(m_managementHost, m_managementPort)) {
|
||||
uint mgmtPort = selectMgmtPort();
|
||||
qDebug() << "OpenVpnProtocol::start mgmt port selected:" << mgmtPort;
|
||||
|
||||
if (!m_managementServer.start(m_managementHost, mgmtPort)) {
|
||||
setLastError(ErrorCode::OpenVpnManagementServerError);
|
||||
return lastError();
|
||||
}
|
||||
|
@ -183,9 +191,9 @@ ErrorCode OpenVpnProtocol::start()
|
|||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
m_openVpnProcess->setProgram(openVpnExecPath());
|
||||
m_openVpnProcess->setProgram(PermittedProcess::OpenVPN);
|
||||
QStringList arguments({"--config" , configPath(),
|
||||
"--management", m_managementHost, QString::number(m_managementPort),
|
||||
"--management", m_managementHost, QString::number(mgmtPort),
|
||||
"--management-client"/*, "--log", vpnLogFileNamePath */
|
||||
});
|
||||
m_openVpnProcess->setArguments(arguments);
|
||||
|
|
|
@ -30,7 +30,6 @@ protected slots:
|
|||
|
||||
private:
|
||||
QString configPath() const;
|
||||
QString openVpnExecPath() const;
|
||||
bool openVpnProcessIsRunning() const;
|
||||
bool sendTermSignal();
|
||||
void readOpenVpnConfiguration(const QJsonObject &configuration);
|
||||
|
@ -47,6 +46,8 @@ private:
|
|||
QString m_configFileName;
|
||||
QTemporaryFile m_configFile;
|
||||
|
||||
uint selectMgmtPort();
|
||||
|
||||
private:
|
||||
void updateRouteGateway(QString line);
|
||||
void updateVpnGateway(const QString &line);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "shadowsocksvpnprotocol.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "utilities.h"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QTcpSocket>
|
||||
#include <QThread>
|
||||
|
||||
|
@ -12,25 +11,20 @@
|
|||
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) :
|
||||
VpnProtocol(configuration, parent)
|
||||
{
|
||||
//m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
|
||||
m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
|
||||
readWireguardConfiguration(configuration);
|
||||
}
|
||||
|
||||
WireguardProtocol::~WireguardProtocol()
|
||||
{
|
||||
//qDebug() << "WireguardProtocol::~WireguardProtocol() 1";
|
||||
WireguardProtocol::stop();
|
||||
QThread::msleep(200);
|
||||
//qDebug() << "WireguardProtocol::~WireguardProtocol() 2";
|
||||
}
|
||||
|
||||
void WireguardProtocol::stop()
|
||||
{
|
||||
//qDebug() << "WireguardProtocol::stop() 1";
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
if (!QFileInfo::exists(wireguardExecPath())) {
|
||||
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
|
||||
qCritical() << "Wireguard executable missing!";
|
||||
setLastError(ErrorCode::ExecutableMissing);
|
||||
return;
|
||||
|
@ -51,7 +45,7 @@ void WireguardProtocol::stop()
|
|||
return;
|
||||
}
|
||||
|
||||
m_wireguardStopProcess->setProgram(wireguardExecPath());
|
||||
m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard);
|
||||
|
||||
|
||||
QStringList arguments({"--remove", configPath()});
|
||||
|
@ -74,7 +68,6 @@ void WireguardProtocol::stop()
|
|||
setConnectionState(VpnProtocol::Disconnected);
|
||||
#endif
|
||||
|
||||
//qDebug() << "WireguardProtocol::stop() 2";
|
||||
}
|
||||
|
||||
void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configuration)
|
||||
|
@ -97,11 +90,6 @@ void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configurat
|
|||
|
||||
}
|
||||
|
||||
//bool WireguardProtocol::openVpnProcessIsRunning() const
|
||||
//{
|
||||
// return Utils::processIsRunning("openvpn");
|
||||
//}
|
||||
|
||||
QString WireguardProtocol::configPath() const
|
||||
{
|
||||
return m_configFileName;
|
||||
|
@ -117,31 +105,17 @@ void WireguardProtocol::updateRouteGateway(QString line)
|
|||
qDebug() << "Set VPN route gateway" << m_routeGateway;
|
||||
}
|
||||
|
||||
QString WireguardProtocol::wireguardExecPath() const
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable("wireguard/wireguard-service", true);
|
||||
#elif defined Q_OS_LINUX
|
||||
return Utils::usrExecutable("wg");
|
||||
#else
|
||||
return Utils::executable("/wireguard", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
ErrorCode WireguardProtocol::start()
|
||||
{
|
||||
//qDebug() << "WireguardProtocol::start() 1";
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
if (!m_isConfigLoaded) {
|
||||
setLastError(ErrorCode::ConfigMissing);
|
||||
return lastError();
|
||||
}
|
||||
|
||||
//qDebug() << "Start Wireguard connection";
|
||||
WireguardProtocol::stop();
|
||||
|
||||
if (!QFileInfo::exists(wireguardExecPath())) {
|
||||
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
|
||||
setLastError(ErrorCode::ExecutableMissing);
|
||||
return lastError();
|
||||
}
|
||||
|
@ -156,7 +130,6 @@ ErrorCode WireguardProtocol::start()
|
|||
m_wireguardStartProcess = IpcClient::CreatePrivilegedProcess();
|
||||
|
||||
if (!m_wireguardStartProcess) {
|
||||
//qWarning() << "IpcProcess replica is not created!";
|
||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
|
@ -168,7 +141,7 @@ ErrorCode WireguardProtocol::start()
|
|||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
|
||||
m_wireguardStartProcess->setProgram(wireguardExecPath());
|
||||
m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard);
|
||||
|
||||
|
||||
QStringList arguments({"--add", configPath()});
|
||||
|
@ -210,8 +183,6 @@ ErrorCode WireguardProtocol::start()
|
|||
m_wireguardStartProcess->start();
|
||||
m_wireguardStartProcess->waitForFinished(10000);
|
||||
|
||||
//qDebug() << "WireguardProtocol::start() 2";
|
||||
|
||||
return ErrorCode::NoError;
|
||||
#else
|
||||
return ErrorCode::NotImplementedError;
|
||||
|
|
|
@ -23,8 +23,6 @@ public:
|
|||
|
||||
private:
|
||||
QString configPath() const;
|
||||
QString wireguardExecPath() const;
|
||||
//bool openVpnProcessIsRunning() const;
|
||||
void readWireguardConfiguration(const QJsonObject &configuration);
|
||||
|
||||
void updateRouteGateway(QString line);
|
||||
|
|
|
@ -159,5 +159,6 @@
|
|||
<file>ui/qml/Controls/SvgButtonType.qml</file>
|
||||
<file>ui/qml/Pages/PageQrDecoderIos.qml</file>
|
||||
<file>server_scripts/website_tor/Dockerfile</file>
|
||||
<file>ui/qml/Pages/PageViewConfig.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
263
client/secure_qsettings.cpp
Normal file
263
client/secure_qsettings.cpp
Normal file
|
@ -0,0 +1,263 @@
|
|||
#include "secure_qsettings.h"
|
||||
#include "platforms/ios/MobileUtils.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QIODevice>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
#include "utilities.h"
|
||||
#include <QRandomGenerator>
|
||||
#include "QAead.h"
|
||||
#include "QBlockCipher.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
|
||||
: QObject{parent},
|
||||
m_settings(organization, application, parent),
|
||||
encryptedKeys({"Servers/serversList"})
|
||||
{
|
||||
bool encrypted = m_settings.value("Conf/encrypted").toBool();
|
||||
|
||||
// convert settings to encrypted for if updated to >= 2.1.0
|
||||
if (encryptionRequired() && ! encrypted) {
|
||||
for (const QString &key : m_settings.allKeys()) {
|
||||
if (encryptedKeys.contains(key)) {
|
||||
const QVariant &val = value(key);
|
||||
setValue(key, val);
|
||||
}
|
||||
}
|
||||
m_settings.setValue("Conf/encrypted", true);
|
||||
m_settings.sync();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
if (m_cache.contains(key)) {
|
||||
return m_cache.value(key);
|
||||
}
|
||||
|
||||
if (!m_settings.contains(key)) return defaultValue;
|
||||
|
||||
QVariant retVal;
|
||||
|
||||
// check if value is not encrypted, v. < 2.0.x
|
||||
retVal = m_settings.value(key);
|
||||
if (retVal.isValid()) {
|
||||
if (retVal.userType() == QVariant::ByteArray &&
|
||||
retVal.toByteArray().mid(0, magicString.size()) == magicString) {
|
||||
|
||||
if (getEncKey().isEmpty() || getEncIv().isEmpty()) {
|
||||
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray encryptedValue = retVal.toByteArray().mid(magicString.size());
|
||||
|
||||
QByteArray decryptedValue = decryptText(encryptedValue);
|
||||
QDataStream ds(&decryptedValue, QIODevice::ReadOnly);
|
||||
|
||||
ds >> retVal;
|
||||
|
||||
if (!retVal.isValid()) {
|
||||
qWarning() << "SecureQSettings::value settings decryption failed";
|
||||
retVal = QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning() << "SecureQSettings::value invalid QVariant value";
|
||||
retVal = QVariant();
|
||||
}
|
||||
|
||||
m_cache.insert(key, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
if (encryptionRequired() && encryptedKeys.contains(key)) {
|
||||
if (!getEncKey().isEmpty() && !getEncIv().isEmpty()) {
|
||||
QByteArray decryptedValue;
|
||||
{
|
||||
QDataStream ds(&decryptedValue, QIODevice::WriteOnly);
|
||||
ds << value;
|
||||
}
|
||||
|
||||
QByteArray encryptedValue = encryptText(decryptedValue);
|
||||
m_settings.setValue(key, magicString + encryptedValue);
|
||||
}
|
||||
else {
|
||||
qCritical() << "SecureQSettings::setValue Encryption required, but key is empty";
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
m_settings.setValue(key, value);
|
||||
}
|
||||
|
||||
m_cache.insert(key, value);
|
||||
sync();
|
||||
}
|
||||
|
||||
void SecureQSettings::remove(const QString &key)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
m_settings.remove(key);
|
||||
m_cache.remove(key);
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
void SecureQSettings::sync()
|
||||
{
|
||||
m_settings.sync();
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::backupAppConfig() const
|
||||
{
|
||||
QJsonObject cfg;
|
||||
|
||||
for (const QString &key : m_settings.allKeys()) {
|
||||
cfg.insert(key, QJsonValue::fromVariant(value(key)));
|
||||
}
|
||||
|
||||
return QJsonDocument(cfg).toJson();
|
||||
}
|
||||
|
||||
bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
||||
{
|
||||
QJsonObject cfg = QJsonDocument::fromJson(json).object();
|
||||
if (cfg.isEmpty()) return false;
|
||||
|
||||
for (const QString &key : cfg.keys()) {
|
||||
setValue(key, cfg.value(key).toVariant());
|
||||
}
|
||||
|
||||
sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QByteArray SecureQSettings::encryptText(const QByteArray& value) const
|
||||
{
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::decryptText(const QByteArray& ba) const
|
||||
{
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
|
||||
}
|
||||
|
||||
bool SecureQSettings::encryptionRequired() const
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
// QtKeyChain failing on Linux
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::getEncKey() const
|
||||
{
|
||||
// load keys from system key storage
|
||||
m_key = getSecTag(settingsKeyTag);
|
||||
|
||||
if (m_key.isEmpty()) {
|
||||
// Create new key
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
QByteArray key = cipher.generateSecureRandomBytes(32);
|
||||
if (key.isEmpty()) {
|
||||
qCritical() << "SecureQSettings::getEncKey Unable to generate new enc key";
|
||||
}
|
||||
|
||||
setSecTag(settingsKeyTag, key);
|
||||
|
||||
// check
|
||||
m_key = getSecTag(settingsKeyTag);
|
||||
if (key != m_key) {
|
||||
qCritical() << "SecureQSettings::getEncKey Unable to store key in keychain" << key.size() << m_key.size();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return m_key;
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::getEncIv() const
|
||||
{
|
||||
// load keys from system key storage
|
||||
m_iv = getSecTag(settingsIvTag);
|
||||
|
||||
if (m_iv.isEmpty()) {
|
||||
// Create new IV
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
QByteArray iv = cipher.generateSecureRandomBytes(32);
|
||||
if (iv.isEmpty()) {
|
||||
qCritical() << "SecureQSettings::getEncIv Unable to generate new enc IV";
|
||||
}
|
||||
setSecTag(settingsIvTag, iv);
|
||||
|
||||
// check
|
||||
m_iv = getSecTag(settingsIvTag);
|
||||
if (iv != m_iv) {
|
||||
qCritical() << "SecureQSettings::getEncIv Unable to store IV in keychain" << iv.size() << m_iv.size();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return m_iv;
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::getSecTag(const QString &tag)
|
||||
{
|
||||
auto job = QSharedPointer<ReadPasswordJob>(new ReadPasswordJob(keyChainName), &QObject::deleteLater);
|
||||
job->setAutoDelete(false);
|
||||
job->setKey(tag);
|
||||
QEventLoop loop;
|
||||
job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop](){
|
||||
loop.quit();
|
||||
});
|
||||
job->start();
|
||||
loop.exec();
|
||||
|
||||
if ( job->error() ) {
|
||||
qCritical() << "SecureQSettings::getSecTag Error:" << job->errorString();
|
||||
}
|
||||
|
||||
return job->binaryData();
|
||||
}
|
||||
|
||||
void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
|
||||
{
|
||||
auto job = QSharedPointer<WritePasswordJob>(new WritePasswordJob(keyChainName), &QObject::deleteLater);
|
||||
job->setAutoDelete(false);
|
||||
job->setKey(tag);
|
||||
job->setBinaryData(data);
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(1000, &loop, SLOT(quit()));
|
||||
job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop](){
|
||||
loop.quit();
|
||||
});
|
||||
job->start();
|
||||
loop.exec();
|
||||
|
||||
if (job->error()) {
|
||||
qCritical() << "SecureQSettings::setSecTag Error:" << job->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
|
56
client/secure_qsettings.h
Normal file
56
client/secure_qsettings.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef SECUREQSETTINGS_H
|
||||
#define SECUREQSETTINGS_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include "keychain.h"
|
||||
|
||||
|
||||
constexpr const char* settingsKeyTag = "settingsKeyTag";
|
||||
constexpr const char* settingsIvTag = "settingsIvTag";
|
||||
constexpr const char* keyChainName = "AmneziaVPN-Keychain";
|
||||
|
||||
|
||||
class SecureQSettings : public QObject
|
||||
{
|
||||
public:
|
||||
explicit SecureQSettings(const QString &organization, const QString &application = QString(), QObject *parent = nullptr);
|
||||
|
||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
void remove(const QString &key);
|
||||
void sync();
|
||||
|
||||
QByteArray backupAppConfig() const;
|
||||
bool restoreAppConfig(const QByteArray &json);
|
||||
|
||||
QByteArray encryptText(const QByteArray &value) const;
|
||||
QByteArray decryptText(const QByteArray& ba) const;
|
||||
|
||||
bool encryptionRequired() const;
|
||||
|
||||
QByteArray getEncKey() const;
|
||||
QByteArray getEncIv() const;
|
||||
|
||||
static QByteArray getSecTag(const QString &tag);
|
||||
static void setSecTag(const QString &tag, const QByteArray &data);
|
||||
|
||||
private:
|
||||
QSettings m_settings;
|
||||
|
||||
mutable QMap<QString, QVariant> m_cache;
|
||||
|
||||
QStringList encryptedKeys; // encode only key listed here
|
||||
|
||||
mutable QByteArray m_key;
|
||||
mutable QByteArray m_iv;
|
||||
|
||||
const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray
|
||||
|
||||
mutable QMutex mutex;
|
||||
};
|
||||
|
||||
#endif // SECUREQSETTINGS_H
|
|
@ -2,12 +2,12 @@
|
|||
#include "settings.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
const char Settings::cloudFlareNs1[] = "1.1.1.1";
|
||||
const char Settings::cloudFlareNs2[] = "1.0.0.1";
|
||||
|
||||
|
||||
Settings::Settings(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
|
||||
|
@ -178,7 +178,6 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai
|
|||
QJsonObject c = protocolConfig(serverIndex, container, proto);
|
||||
c.remove(config_key::last_config);
|
||||
setProtocolConfig(serverIndex, container, proto, c);
|
||||
qDebug() << "Settings::clearLastConnectionConfig for" << serverIndex << container << proto;
|
||||
}
|
||||
|
||||
bool Settings::haveAuthData(int serverIndex) const
|
||||
|
@ -292,60 +291,10 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
|
|||
setVpnSites(mode, sitesMap);
|
||||
}
|
||||
|
||||
//void Settings::addVpnForwardSite(const QString &site, const QString &ip)
|
||||
//{
|
||||
// auto sites = vpnForwardSites();
|
||||
// QStringList l = sites.value(site).toStringList();
|
||||
// if (!l.contains(ip)) {
|
||||
// l.append(ip);
|
||||
// setVpnForwardSites(sites);
|
||||
// }
|
||||
//}
|
||||
|
||||
//QStringList Settings::getVpnForwardIps() const
|
||||
//{
|
||||
// QStringList ips;
|
||||
// const QVariantMap &m = vpnForwardSites();
|
||||
// for (const QVariant &v : m) {
|
||||
// ips.append(v.toStringList());
|
||||
// }
|
||||
// ips.removeDuplicates();
|
||||
// return ips;
|
||||
//}
|
||||
|
||||
//void Settings::addVpnExceptSite(const QString &site, const QString &ip)
|
||||
//{
|
||||
// auto sites = vpnExceptSites();
|
||||
// QStringList l = sites.value(site).toStringList();
|
||||
// if (!l.contains(ip)) {
|
||||
// l.append(ip);
|
||||
// setVpnExceptSites(sites);
|
||||
// }
|
||||
//}
|
||||
|
||||
//QStringList Settings::getVpnExceptIps() const
|
||||
//{
|
||||
// QStringList ips;
|
||||
// const QVariantMap &m = vpnExceptSites();
|
||||
// for (const QVariant &v : m) {
|
||||
// ips.append(v.toStringList());
|
||||
// }
|
||||
// ips.removeDuplicates();
|
||||
// return ips;
|
||||
//}
|
||||
|
||||
QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); }
|
||||
|
||||
QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); }
|
||||
|
||||
//void Settings::setServerCredentials(const ServerCredentials &credentials)
|
||||
//{
|
||||
// setServerName(credentials.hostName);
|
||||
// setServerPort(credentials.port);
|
||||
// setUserName(credentials.userName);
|
||||
// setPassword(credentials.password);
|
||||
//}
|
||||
|
||||
ServerCredentials Settings::defaultServerCredentials() const
|
||||
{
|
||||
return serverCredentials(defaultServerIndex());
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "core/defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "secure_qsettings.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
|
@ -25,7 +26,6 @@ public:
|
|||
|
||||
ServerCredentials defaultServerCredentials() const;
|
||||
ServerCredentials serverCredentials(int index) const;
|
||||
//void setServerCredentials(const ServerCredentials &credentials);
|
||||
|
||||
QJsonArray serversArray() const { return QJsonDocument::fromJson(m_settings.value("Servers/serversList").toByteArray()).array(); }
|
||||
void setServersArray(const QJsonArray &servers) { m_settings.setValue("Servers/serversList", QJsonDocument(servers).toJson()); }
|
||||
|
@ -110,13 +110,11 @@ public:
|
|||
// static constexpr char openNicNs5[] = "94.103.153.176";
|
||||
// static constexpr char openNicNs13[] = "144.76.103.143";
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); }
|
||||
bool restoreAppConfig(const QByteArray &cfg) { return m_settings.restoreAppConfig(cfg); }
|
||||
|
||||
private:
|
||||
QSettings m_settings;
|
||||
SecureQSettings m_settings;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "containers_model.h"
|
||||
|
||||
ContainersModel::ContainersModel(QObject *parent) :
|
||||
ContainersModel::ContainersModel(std::shared_ptr<Settings> settings, QObject *parent) :
|
||||
m_settings(settings),
|
||||
QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
|
@ -37,13 +38,13 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
|
|||
return ContainerProps::containerDescriptions().value(c);
|
||||
}
|
||||
if (role == DefaultRole) {
|
||||
return c == m_settings.defaultContainer(m_selectedServerIndex);
|
||||
return c == m_settings->defaultContainer(m_selectedServerIndex);
|
||||
}
|
||||
if (role == ServiceTypeRole) {
|
||||
return ContainerProps::containerService(c);
|
||||
}
|
||||
if (role == IsInstalledRole) {
|
||||
return m_settings.containers(m_selectedServerIndex).contains(c);
|
||||
return m_settings->containers(m_selectedServerIndex).contains(c);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class ContainersModel : public QAbstractListModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ContainersModel(QObject *parent = nullptr);
|
||||
ContainersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
public:
|
||||
enum SiteRoles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
|
@ -33,7 +33,7 @@ protected:
|
|||
|
||||
private:
|
||||
int m_selectedServerIndex;
|
||||
Settings m_settings;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
};
|
||||
|
||||
#endif // CONTAINERS_MODEL_H
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "protocols_model.h"
|
||||
|
||||
ProtocolsModel::ProtocolsModel(QObject *parent) :
|
||||
ProtocolsModel::ProtocolsModel(std::shared_ptr<Settings> settings, QObject *parent) :
|
||||
m_settings(settings),
|
||||
QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class ProtocolsModel : public QAbstractListModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProtocolsModel(QObject *parent = nullptr);
|
||||
ProtocolsModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
public:
|
||||
enum SiteRoles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
|
@ -34,7 +34,7 @@ protected:
|
|||
private:
|
||||
int m_selectedServerIndex;
|
||||
DockerContainer m_selectedDockerContainer;
|
||||
Settings m_settings;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
};
|
||||
|
||||
#endif // PROTOCOLS_MODEL_H
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "sites_model.h"
|
||||
|
||||
SitesModel::SitesModel(Settings::RouteMode mode, QObject *parent)
|
||||
SitesModel::SitesModel(std::shared_ptr<Settings> settings, Settings::RouteMode mode, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
m_settings(settings),
|
||||
m_mode(mode)
|
||||
{
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ void SitesModel::genCache() const
|
|||
qDebug() << "SitesModel::genCache";
|
||||
m_ipsCache.clear();
|
||||
|
||||
const QVariantMap &sites = m_settings.vpnSites(m_mode);
|
||||
const QVariantMap &sites = m_settings->vpnSites(m_mode);
|
||||
auto i = sites.constBegin();
|
||||
while (i != sites.constEnd()) {
|
||||
m_ipsCache.append(qMakePair(i.key(), i.value().toString()));
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
IpRole
|
||||
};
|
||||
|
||||
explicit SitesModel(Settings::RouteMode mode, QObject *parent = nullptr);
|
||||
explicit SitesModel(std::shared_ptr<Settings> settings, Settings::RouteMode mode, QObject *parent = nullptr);
|
||||
void resetCache();
|
||||
|
||||
// Basic functionality:
|
||||
|
@ -32,7 +32,7 @@ private:
|
|||
|
||||
private:
|
||||
Settings::RouteMode m_mode;
|
||||
Settings m_settings;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
mutable QVector<QPair<QString, QString>> m_ipsCache;
|
||||
mutable bool m_cacheReady = false;
|
||||
|
|
|
@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
|
|||
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
|
||||
GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
|
||||
ServerContainers, ServersList, ShareConnection, Sites,
|
||||
ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About};
|
||||
ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig};
|
||||
Q_ENUM_NS(Page)
|
||||
|
||||
static void declareQmlPageEnum() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardPaths>
|
||||
|
||||
using namespace amnezia;
|
||||
|
@ -25,9 +26,9 @@ AppSettingsLogic::AppSettingsLogic(UiLogic *logic, QObject *parent):
|
|||
void AppSettingsLogic::onUpdatePage()
|
||||
{
|
||||
set_checkBoxAutostartChecked(Autostart::isAutostart());
|
||||
set_checkBoxAutoConnectChecked(m_settings.isAutoConnect());
|
||||
set_checkBoxStartMinimizedChecked(m_settings.isStartMinimized());
|
||||
set_checkBoxSaveLogsChecked(m_settings.isSaveLogs());
|
||||
set_checkBoxAutoConnectChecked(m_settings->isAutoConnect());
|
||||
set_checkBoxStartMinimizedChecked(m_settings->isStartMinimized());
|
||||
set_checkBoxSaveLogsChecked(m_settings->isSaveLogs());
|
||||
|
||||
QString ver = QString("%1: %2 (%3)")
|
||||
.arg(tr("Software version"))
|
||||
|
@ -46,17 +47,17 @@ void AppSettingsLogic::onCheckBoxAutostartToggled(bool checked)
|
|||
|
||||
void AppSettingsLogic::onCheckBoxAutoconnectToggled(bool checked)
|
||||
{
|
||||
m_settings.setAutoConnect(checked);
|
||||
m_settings->setAutoConnect(checked);
|
||||
}
|
||||
|
||||
void AppSettingsLogic::onCheckBoxStartMinimizedToggled(bool checked)
|
||||
{
|
||||
m_settings.setStartMinimized(checked);
|
||||
m_settings->setStartMinimized(checked);
|
||||
}
|
||||
|
||||
void AppSettingsLogic::onCheckBoxSaveLogsCheckedToggled(bool checked)
|
||||
{
|
||||
m_settings.setSaveLogs(checked);
|
||||
m_settings->setSaveLogs(checked);
|
||||
}
|
||||
|
||||
void AppSettingsLogic::onPushButtonOpenLogsClicked()
|
||||
|
@ -74,3 +75,32 @@ void AppSettingsLogic::onPushButtonClearLogsClicked()
|
|||
Debug::clearLogs();
|
||||
Debug::clearServiceLogs();
|
||||
}
|
||||
|
||||
void AppSettingsLogic::onPushButtonBackupAppConfigClicked()
|
||||
{
|
||||
uiLogic()->saveTextFile("Backup application config", "AmneziaVPN.backup", ".backup", m_settings->backupAppConfig());
|
||||
}
|
||||
|
||||
void AppSettingsLogic::onPushButtonRestoreAppConfigClicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open backup"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup");
|
||||
|
||||
if (fileName.isEmpty()) return;
|
||||
|
||||
QFile file(fileName);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QByteArray data = file.readAll();
|
||||
|
||||
bool ok = m_settings->restoreAppConfig(data);
|
||||
if (ok) {
|
||||
emit uiLogic()->goToPage(Page::Vpn);
|
||||
emit uiLogic()->setStartPage(Page::Vpn);
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(nullptr, APPLICATION_NAME,
|
||||
tr("Can't import config, file is corrupted."));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ public:
|
|||
Q_INVOKABLE void onPushButtonExportLogsClicked();
|
||||
Q_INVOKABLE void onPushButtonClearLogsClicked();
|
||||
|
||||
Q_INVOKABLE void onPushButtonBackupAppConfigClicked();
|
||||
Q_INVOKABLE void onPushButtonRestoreAppConfigClicked();
|
||||
|
||||
|
||||
public:
|
||||
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
|
||||
~AppSettingsLogic() = default;
|
||||
|
|
|
@ -12,28 +12,28 @@ GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent):
|
|||
|
||||
void GeneralSettingsLogic::onUpdatePage()
|
||||
{
|
||||
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
|
||||
uiLogic()->selectedServerIndex = m_settings->defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||
|
||||
set_pushButtonGeneralSettingsShareConnectionEnable(m_settings.haveAuthData(m_settings.defaultServerIndex()));
|
||||
set_pushButtonGeneralSettingsShareConnectionEnable(m_settings->haveAuthData(m_settings->defaultServerIndex()));
|
||||
}
|
||||
|
||||
void GeneralSettingsLogic::onPushButtonGeneralSettingsServerSettingsClicked()
|
||||
{
|
||||
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
|
||||
uiLogic()->selectedServerIndex = m_settings->defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||
|
||||
emit uiLogic()->goToPage(Page::ServerSettings);
|
||||
}
|
||||
|
||||
void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked()
|
||||
{
|
||||
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex);
|
||||
uiLogic()->selectedServerIndex = m_settings->defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex);
|
||||
|
||||
qobject_cast<ProtocolsModel *>(uiLogic()->protocolsModel())->setSelectedServerIndex(uiLogic()->selectedServerIndex);
|
||||
qobject_cast<ProtocolsModel *>(uiLogic()->protocolsModel())->setSelectedDockerContainer(uiLogic()->selectedDockerContainer);
|
||||
|
||||
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
emit uiLogic()->goToPage(Page::ShareConnection);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "defines.h"
|
||||
#include "utilities.h"
|
||||
#include "settings.h"
|
||||
|
||||
NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent),
|
||||
|
@ -13,39 +14,39 @@ NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
|
|||
|
||||
void NetworkSettingsLogic::onUpdatePage()
|
||||
{
|
||||
set_checkBoxUseAmneziaDnsChecked(m_settings.useAmneziaDns());
|
||||
set_checkBoxUseAmneziaDnsChecked(m_settings->useAmneziaDns());
|
||||
|
||||
set_lineEditDns1Text(m_settings.primaryDns());
|
||||
set_lineEditDns2Text(m_settings.secondaryDns());
|
||||
set_lineEditDns1Text(m_settings->primaryDns());
|
||||
set_lineEditDns2Text(m_settings->secondaryDns());
|
||||
}
|
||||
|
||||
void NetworkSettingsLogic::onLineEditDns1EditFinished(const QString &text)
|
||||
{
|
||||
if (ipAddressRegex().match(text).hasMatch()) {
|
||||
m_settings.setPrimaryDns(text);
|
||||
m_settings->setPrimaryDns(text);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSettingsLogic::onLineEditDns2EditFinished(const QString &text)
|
||||
{
|
||||
if (ipAddressRegex().match(text).hasMatch()) {
|
||||
m_settings.setSecondaryDns(text);
|
||||
m_settings->setSecondaryDns(text);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSettingsLogic::onPushButtonResetDns1Clicked()
|
||||
{
|
||||
m_settings.setPrimaryDns(m_settings.cloudFlareNs1);
|
||||
m_settings->setPrimaryDns(m_settings->cloudFlareNs1);
|
||||
onUpdatePage();
|
||||
}
|
||||
|
||||
void NetworkSettingsLogic::onPushButtonResetDns2Clicked()
|
||||
{
|
||||
m_settings.setSecondaryDns(m_settings.cloudFlareNs2);
|
||||
m_settings->setSecondaryDns(m_settings->cloudFlareNs2);
|
||||
onUpdatePage();
|
||||
}
|
||||
|
||||
void NetworkSettingsLogic::onCheckBoxUseAmneziaDnsToggled(bool checked)
|
||||
{
|
||||
m_settings.setUseAmneziaDns(checked);
|
||||
m_settings->setUseAmneziaDns(checked);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "PageLogicBase.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
class UiLogic;
|
||||
|
||||
class NetworkSettingsLogic : public PageLogicBase
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define NEW_SERVER_PROTOCOLS_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#include "PageLogicBase.h"
|
||||
|
||||
#include "ui/uilogic.h"
|
||||
#include "settings.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
|
||||
PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent):
|
||||
QObject(parent),
|
||||
m_pageEnabled{true},
|
||||
m_uiLogic(logic)
|
||||
{
|
||||
|
||||
m_settings = logic->m_settings;
|
||||
m_configurator = logic->m_configurator;
|
||||
m_serverController = logic->m_serverController;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
#ifndef PAGE_LOGIC_BASE_H
|
||||
#define PAGE_LOGIC_BASE_H
|
||||
|
||||
#include "settings.h"
|
||||
#include "../pages.h"
|
||||
#include "../property_helper.h"
|
||||
|
||||
using namespace amnezia;
|
||||
using namespace PageEnumNS;
|
||||
|
||||
class UiLogic;
|
||||
class Settings;
|
||||
class VpnConfigurator;
|
||||
class ServerController;
|
||||
|
||||
class PageLogicBase : public QObject
|
||||
{
|
||||
|
@ -22,10 +23,12 @@ public:
|
|||
Q_INVOKABLE virtual void onUpdatePage() {}
|
||||
|
||||
protected:
|
||||
UiLogic *m_uiLogic;
|
||||
UiLogic *uiLogic() const { return m_uiLogic; }
|
||||
|
||||
Settings m_settings;
|
||||
UiLogic *m_uiLogic;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||
std::shared_ptr<ServerController> m_serverController;
|
||||
|
||||
signals:
|
||||
void updatePage();
|
||||
|
|
|
@ -54,7 +54,7 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code)
|
|||
data.append(m_chunks.value(i));
|
||||
}
|
||||
|
||||
bool ok = uiLogic()->startPageLogic()->importConnectionFromQr(data);
|
||||
bool ok = uiLogic()->pageLogic<StartPageLogic>()->importConnectionFromQr(data);
|
||||
if (ok) {
|
||||
set_detectingEnabled(false);
|
||||
emit stopDecode();
|
||||
|
@ -67,7 +67,7 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code)
|
|||
}
|
||||
}
|
||||
else {
|
||||
bool ok = uiLogic()->startPageLogic()->importConnectionFromQr(ba);
|
||||
bool ok = uiLogic()->pageLogic<StartPageLogic>()->importConnectionFromQr(ba);
|
||||
if (ok) {
|
||||
set_detectingEnabled(false);
|
||||
emit stopDecode();
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <functional>
|
||||
#include "PageLogicBase.h"
|
||||
#include "core/defs.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
|
|
@ -36,64 +36,64 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c,
|
|||
{
|
||||
qDebug()<< "ServerContainersLogic::onPushButtonProtoSettingsClicked" << c << p;
|
||||
uiLogic()->selectedDockerContainer = c;
|
||||
uiLogic()->protocolLogic(p)->updateProtocolPage(m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p),
|
||||
uiLogic()->protocolLogic(p)->updateProtocolPage(m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p),
|
||||
uiLogic()->selectedDockerContainer,
|
||||
m_settings.haveAuthData(uiLogic()->selectedServerIndex));
|
||||
m_settings->haveAuthData(uiLogic()->selectedServerIndex));
|
||||
|
||||
emit uiLogic()->goToProtocolPage(p);
|
||||
}
|
||||
|
||||
void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c)
|
||||
{
|
||||
if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == c) return;
|
||||
if (m_settings->defaultContainer(uiLogic()->selectedServerIndex) == c) return;
|
||||
|
||||
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
|
||||
m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c);
|
||||
uiLogic()->onUpdateAllPages();
|
||||
|
||||
if (uiLogic()->selectedServerIndex != m_settings.defaultServerIndex()) return;
|
||||
if (uiLogic()->selectedServerIndex != m_settings->defaultServerIndex()) return;
|
||||
if (!uiLogic()->m_vpnConnection) return;
|
||||
if (!uiLogic()->m_vpnConnection->isConnected()) return;
|
||||
|
||||
uiLogic()->vpnLogic()->onDisconnect();
|
||||
uiLogic()->vpnLogic()->onConnect();
|
||||
uiLogic()->pageLogic<VpnLogic>()->onDisconnect();
|
||||
uiLogic()->pageLogic<VpnLogic>()->onConnect();
|
||||
}
|
||||
|
||||
void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c)
|
||||
{
|
||||
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, c);
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->selectedServerIndex, c);
|
||||
emit uiLogic()->goToPage(Page::ShareConnection);
|
||||
}
|
||||
|
||||
void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container)
|
||||
{
|
||||
//buttonSetEnabledFunc(false);
|
||||
ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), container);
|
||||
m_settings.removeContainerConfig(uiLogic()->selectedServerIndex, container);
|
||||
ErrorCode e = m_serverController->removeContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), container);
|
||||
m_settings->removeContainerConfig(uiLogic()->selectedServerIndex, container);
|
||||
//buttonSetEnabledFunc(true);
|
||||
|
||||
if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == container) {
|
||||
const auto &c = m_settings.containers(uiLogic()->selectedServerIndex);
|
||||
if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first());
|
||||
if (m_settings->defaultContainer(uiLogic()->selectedServerIndex) == container) {
|
||||
const auto &c = m_settings->containers(uiLogic()->selectedServerIndex);
|
||||
if (c.isEmpty()) m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
else m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first());
|
||||
}
|
||||
uiLogic()->onUpdateAllPages();
|
||||
}
|
||||
|
||||
void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp)
|
||||
{
|
||||
QJsonObject config = ServerController::createContainerInitialConfig(c, port, tp);
|
||||
QJsonObject config = m_serverController->createContainerInitialConfig(c, port, tp);
|
||||
|
||||
emit uiLogic()->goToPage(Page::ServerConfiguringProgress);
|
||||
qApp->processEvents();
|
||||
|
||||
ErrorCode e = uiLogic()->serverConfiguringProgressLogic()->doInstallAction([this, c, &config](){
|
||||
return ServerController::setupContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), c, config);
|
||||
ErrorCode e = uiLogic()->pageLogic<ServerConfiguringProgressLogic>()->doInstallAction([this, c, &config](){
|
||||
return m_serverController->setupContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), c, config);
|
||||
});
|
||||
|
||||
if (!e) {
|
||||
m_settings.setContainerConfig(uiLogic()->selectedServerIndex, c, config);
|
||||
m_settings->setContainerConfig(uiLogic()->selectedServerIndex, c, config);
|
||||
if (ContainerProps::containerService(c) == ServiceType::Vpn) {
|
||||
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
|
||||
m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SERVER_CONTAINERS_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ ServerListLogic::ServerListLogic(UiLogic *logic, QObject *parent):
|
|||
|
||||
void ServerListLogic::onServerListPushbuttonDefaultClicked(int index)
|
||||
{
|
||||
m_settings.setDefaultServer(index);
|
||||
m_settings->setDefaultServer(index);
|
||||
uiLogic()->onUpdateAllPages();
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ void ServerListLogic::onServerListPushbuttonSettingsClicked(int index)
|
|||
|
||||
void ServerListLogic::onUpdatePage()
|
||||
{
|
||||
const QJsonArray &servers = m_settings.serversArray();
|
||||
int defaultServer = m_settings.defaultServerIndex();
|
||||
const QJsonArray &servers = m_settings->serversArray();
|
||||
int defaultServer = m_settings->defaultServerIndex();
|
||||
std::vector<ServerModelContent> serverListContent;
|
||||
for(int i = 0; i < servers.size(); i++) {
|
||||
ServerModelContent c;
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
#include <core/servercontroller.h>
|
||||
#include <QTimer>
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <QAndroidJniObject>
|
||||
#include <QAndroidJniEnvironment>
|
||||
#include <QtAndroid>
|
||||
#endif
|
||||
|
||||
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent),
|
||||
m_labelWaitInfoVisible{true},
|
||||
|
@ -26,10 +32,10 @@ void ServerSettingsLogic::onUpdatePage()
|
|||
{
|
||||
set_labelWaitInfoVisible(false);
|
||||
set_labelWaitInfoText("");
|
||||
set_pushButtonClearVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
|
||||
set_pushButtonClearClientCacheVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
|
||||
set_pushButtonShareFullVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
|
||||
const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex);
|
||||
set_pushButtonClearVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex));
|
||||
set_pushButtonClearClientCacheVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex));
|
||||
set_pushButtonShareFullVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex));
|
||||
const QJsonObject &server = m_settings->server(uiLogic()->selectedServerIndex);
|
||||
const QString &port = server.value(config_key::port).toString();
|
||||
set_labelServerText(QString("%1@%2%3%4")
|
||||
.arg(server.value(config_key::userName).toString())
|
||||
|
@ -38,7 +44,7 @@ void ServerSettingsLogic::onUpdatePage()
|
|||
.arg(port));
|
||||
set_lineEditDescriptionText(server.value(config_key::description).toString());
|
||||
|
||||
DockerContainer selectedContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex);
|
||||
DockerContainer selectedContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex);
|
||||
QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer);
|
||||
set_labelCurrentVpnProtocolText(tr("Service: ") + selectedContainerName);
|
||||
}
|
||||
|
@ -48,14 +54,14 @@ void ServerSettingsLogic::onPushButtonClearServer()
|
|||
set_pageEnabled(false);
|
||||
set_pushButtonClearText(tr("Uninstalling Amnezia software..."));
|
||||
|
||||
if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex) {
|
||||
uiLogic()->vpnLogic()->onDisconnect();
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) {
|
||||
uiLogic()->pageLogic<VpnLogic>()->onDisconnect();
|
||||
}
|
||||
|
||||
ErrorCode e = ServerController::removeAllContainers(m_settings.serverCredentials(uiLogic()->selectedServerIndex));
|
||||
ServerController::disconnectFromHost(m_settings.serverCredentials(uiLogic()->selectedServerIndex));
|
||||
ErrorCode e = m_serverController->removeAllContainers(m_settings->serverCredentials(uiLogic()->selectedServerIndex));
|
||||
m_serverController->disconnectFromHost(m_settings->serverCredentials(uiLogic()->selectedServerIndex));
|
||||
if (e) {
|
||||
uiLogic()->setDialogConnectErrorText(
|
||||
uiLogic()->set_dialogConnectErrorText(
|
||||
tr("Error occurred while configuring server.") + "\n" +
|
||||
errorString(e) + "\n" +
|
||||
tr("See logs for details."));
|
||||
|
@ -66,8 +72,8 @@ void ServerSettingsLogic::onPushButtonClearServer()
|
|||
set_labelWaitInfoText(tr("Amnezia server successfully uninstalled"));
|
||||
}
|
||||
|
||||
m_settings.setContainers(uiLogic()->selectedServerIndex, {});
|
||||
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
m_settings->setContainers(uiLogic()->selectedServerIndex, {});
|
||||
m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
|
||||
set_pageEnabled(true);
|
||||
set_pushButtonClearText(tr("Clear server from Amnezia software"));
|
||||
|
@ -75,27 +81,27 @@ void ServerSettingsLogic::onPushButtonClearServer()
|
|||
|
||||
void ServerSettingsLogic::onPushButtonForgetServer()
|
||||
{
|
||||
if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) {
|
||||
uiLogic()->vpnLogic()->onDisconnect();
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) {
|
||||
uiLogic()->pageLogic<VpnLogic>()->onDisconnect();
|
||||
}
|
||||
m_settings.removeServer(uiLogic()->selectedServerIndex);
|
||||
m_settings->removeServer(uiLogic()->selectedServerIndex);
|
||||
|
||||
if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex) {
|
||||
m_settings.setDefaultServer(0);
|
||||
if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) {
|
||||
m_settings->setDefaultServer(0);
|
||||
}
|
||||
else if (m_settings.defaultServerIndex() > uiLogic()->selectedServerIndex) {
|
||||
m_settings.setDefaultServer(m_settings.defaultServerIndex() - 1);
|
||||
else if (m_settings->defaultServerIndex() > uiLogic()->selectedServerIndex) {
|
||||
m_settings->setDefaultServer(m_settings->defaultServerIndex() - 1);
|
||||
}
|
||||
|
||||
if (m_settings.serversCount() == 0) {
|
||||
m_settings.setDefaultServer(-1);
|
||||
if (m_settings->serversCount() == 0) {
|
||||
m_settings->setDefaultServer(-1);
|
||||
}
|
||||
|
||||
|
||||
uiLogic()->selectedServerIndex = -1;
|
||||
uiLogic()->onUpdateAllPages();
|
||||
|
||||
if (m_settings.serversCount() == 0) {
|
||||
if (m_settings->serversCount() == 0) {
|
||||
uiLogic()->setStartPage(Page::Start);
|
||||
}
|
||||
else {
|
||||
|
@ -107,9 +113,9 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked()
|
|||
{
|
||||
set_pushButtonClearClientCacheText(tr("Cache cleared"));
|
||||
|
||||
const auto &containers = m_settings.containers(uiLogic()->selectedServerIndex);
|
||||
const auto &containers = m_settings->containers(uiLogic()->selectedServerIndex);
|
||||
for (DockerContainer container: containers.keys()) {
|
||||
m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, container);
|
||||
m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, container);
|
||||
}
|
||||
|
||||
QTimer::singleShot(3000, this, [this]() {
|
||||
|
@ -120,14 +126,47 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked()
|
|||
void ServerSettingsLogic::onLineEditDescriptionEditingFinished()
|
||||
{
|
||||
const QString &newText = lineEditDescriptionText();
|
||||
QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex);
|
||||
QJsonObject server = m_settings->server(uiLogic()->selectedServerIndex);
|
||||
server.insert(config_key::description, newText);
|
||||
m_settings.editServer(uiLogic()->selectedServerIndex, server);
|
||||
m_settings->editServer(uiLogic()->selectedServerIndex, server);
|
||||
uiLogic()->onUpdateAllPages();
|
||||
}
|
||||
|
||||
void ServerSettingsLogic::onPushButtonShareFullClicked()
|
||||
#if defined(Q_OS_ANDROID)
|
||||
/* Auth result handler for Android */
|
||||
void authResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
|
||||
{
|
||||
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
|
||||
|
||||
if (resultCode == -1) { //ResultOK
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(m_serverIndex, DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ServerSettingsLogic::onPushButtonShareFullClicked()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
/* We use builtin keyguard for ssh key export protection on Android */
|
||||
auto appContext = QtAndroid::androidActivity().callObjectMethod(
|
||||
"getApplicationContext", "()Landroid/content/Context;");
|
||||
if (appContext.isValid()) {
|
||||
QAndroidActivityResultReceiver *receiver = new authResultReceiver(uiLogic(), uiLogic()->selectedServerIndex);
|
||||
auto intent = QAndroidJniObject::callStaticObjectMethod(
|
||||
"org/amnezia/vpn/AuthHelper", "getAuthIntent",
|
||||
"(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
|
||||
if (intent.isValid()) {
|
||||
if (intent.object<jobject>() != nullptr) {
|
||||
QtAndroid::startActivity(intent.object<jobject>(), 1, receiver);
|
||||
}
|
||||
} else {
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
}
|
||||
}
|
||||
#else
|
||||
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None);
|
||||
emit uiLogic()->goToShareProtocolPage(Proto::Any);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
#include "PageLogicBase.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <QAndroidActivityResultReceiver>
|
||||
#endif
|
||||
|
||||
class UiLogic;
|
||||
|
||||
class ServerSettingsLogic : public PageLogicBase
|
||||
|
@ -34,4 +38,25 @@ public:
|
|||
~ServerSettingsLogic() = default;
|
||||
|
||||
};
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
/* Auth result handler for Android */
|
||||
class authResultReceiver final : public PageLogicBase, public QAndroidActivityResultReceiver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
authResultReceiver(UiLogic *uiLogic, int serverIndex , QObject *parent = nullptr) : PageLogicBase(uiLogic, parent) {
|
||||
m_serverIndex = serverIndex;
|
||||
}
|
||||
~authResultReceiver() {}
|
||||
|
||||
public:
|
||||
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
|
||||
|
||||
private:
|
||||
int m_serverIndex;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // SERVER_SETTINGS_LOGIC_H
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#include <QBuffer>
|
||||
#include <QImage>
|
||||
#include <QDataStream>
|
||||
//#include <QZXing>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "QZXing.h"
|
||||
#include "QZXingImageProvider.h"
|
||||
//#include "QZXingFilter.h"
|
||||
|
||||
#include "qrcodegen.hpp"
|
||||
|
||||
#include "ShareConnectionLogic.h"
|
||||
|
||||
|
@ -21,6 +19,7 @@
|
|||
#include "defines.h"
|
||||
#include "core/defs.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include <functional>
|
||||
|
||||
#include "../uilogic.h"
|
||||
|
@ -29,6 +28,8 @@
|
|||
#include <math.h>
|
||||
#endif
|
||||
|
||||
using namespace qrcodegen;
|
||||
|
||||
ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent),
|
||||
m_textEditShareOpenVpnCodeText{},
|
||||
|
@ -73,19 +74,19 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
|
|||
|
||||
// Full access
|
||||
if (shareFullAccess()) {
|
||||
serverConfig = m_settings.server(serverIndex);
|
||||
serverConfig = m_settings->server(serverIndex);
|
||||
}
|
||||
// Container share
|
||||
else {
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
QJsonObject containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
QJsonObject containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
for (Proto p: ContainerProps::protocolsForContainer(container)) {
|
||||
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, p);
|
||||
QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, p);
|
||||
|
||||
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, container, containerConfig, p, &e);
|
||||
QString cfg = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, p, &e);
|
||||
if (e) {
|
||||
cfg = "Error generating config";
|
||||
break;
|
||||
|
@ -96,14 +97,14 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
|
|||
|
||||
QByteArray ba;
|
||||
if (!e) {
|
||||
serverConfig = m_settings.server(serverIndex);
|
||||
serverConfig = m_settings->server(serverIndex);
|
||||
serverConfig.remove(config_key::userName);
|
||||
serverConfig.remove(config_key::password);
|
||||
serverConfig.remove(config_key::port);
|
||||
serverConfig.insert(config_key::containers, QJsonArray {containerConfig});
|
||||
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
|
||||
|
||||
auto dns = VpnConfigurator::getDnsForConfig(serverIndex);
|
||||
auto dns = m_configurator->getDnsForConfig(serverIndex);
|
||||
serverConfig.insert(config_key::dns1, dns.first);
|
||||
serverConfig.insert(config_key::dns2, dns.second);
|
||||
|
||||
|
@ -129,13 +130,13 @@ void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked()
|
|||
{
|
||||
int serverIndex = uiLogic()->selectedServerIndex;
|
||||
DockerContainer container = uiLogic()->selectedDockerContainer;
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
|
||||
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, &e);
|
||||
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg);
|
||||
QString cfg = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &e);
|
||||
cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg);
|
||||
|
||||
set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString());
|
||||
}
|
||||
|
@ -144,16 +145,16 @@ void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked()
|
|||
{
|
||||
int serverIndex = uiLogic()->selectedServerIndex;
|
||||
DockerContainer container = uiLogic()->selectedDockerContainer;
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
|
||||
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Proto::ShadowSocks);
|
||||
QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, Proto::ShadowSocks);
|
||||
QString cfg = protoConfig.value(config_key::last_config).toString();
|
||||
|
||||
if (cfg.isEmpty()) {
|
||||
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e);
|
||||
cfg = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, &e);
|
||||
}
|
||||
|
||||
QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
|
||||
|
@ -167,8 +168,10 @@ void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked()
|
|||
ssString = "ss://" + ssString.toUtf8().toBase64();
|
||||
set_lineEditShareShadowSocksStringText(ssString);
|
||||
|
||||
QImage qr = QZXing::encodeData(ssString.toUtf8(), QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L);
|
||||
set_shareShadowSocksQrCodeText(imageToBase64(qr));
|
||||
QrCode qr = QrCode::encodeText(ssString.toUtf8(), QrCode::Ecc::LOW);
|
||||
QString svg = QString::fromStdString(toSvgString(qr, 0));
|
||||
|
||||
set_shareShadowSocksQrCodeText(svgToBase64(svg));
|
||||
|
||||
QString humanString = QString("Server: %3\n"
|
||||
"Port: %4\n"
|
||||
|
@ -186,16 +189,16 @@ void ShareConnectionLogic::onPushButtonShareCloakGenerateClicked()
|
|||
{
|
||||
int serverIndex = uiLogic()->selectedServerIndex;
|
||||
DockerContainer container = uiLogic()->selectedDockerContainer;
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
|
||||
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Proto::Cloak);
|
||||
QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, Proto::Cloak);
|
||||
QString cfg = protoConfig.value(config_key::last_config).toString();
|
||||
|
||||
if (cfg.isEmpty()) {
|
||||
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e);
|
||||
cfg = m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &e);
|
||||
}
|
||||
|
||||
QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
|
||||
|
@ -209,48 +212,47 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked()
|
|||
{
|
||||
int serverIndex = uiLogic()->selectedServerIndex;
|
||||
DockerContainer container = uiLogic()->selectedDockerContainer;
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
|
||||
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
QString cfg = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, &e);
|
||||
QString cfg = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, &e);
|
||||
if (e) {
|
||||
QMessageBox::warning(nullptr, APPLICATION_NAME,
|
||||
tr("Error occurred while configuring server.") + "\n" +
|
||||
errorString(e));
|
||||
return;
|
||||
}
|
||||
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg);
|
||||
cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg);
|
||||
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString();
|
||||
|
||||
set_textEditShareWireGuardCodeText(cfg);
|
||||
|
||||
QImage qr = QZXing::encodeData(cfg.toUtf8(), QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L);
|
||||
QrCode qr = QrCode::encodeText(cfg.toUtf8(), QrCode::Ecc::LOW);
|
||||
QString svg = QString::fromStdString(toSvgString(qr, 0));
|
||||
|
||||
set_shareWireGuardQrCodeText(imageToBase64(qr));
|
||||
set_shareWireGuardQrCodeText(svgToBase64(svg));
|
||||
}
|
||||
|
||||
void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked()
|
||||
{
|
||||
int serverIndex = uiLogic()->selectedServerIndex;
|
||||
DockerContainer container = uiLogic()->selectedDockerContainer;
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
|
||||
//const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
Ikev2Configurator::ConnectionData connData = m_configurator->ikev2Configurator->prepareIkev2Config(credentials, container);
|
||||
|
||||
Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container);
|
||||
|
||||
QString cfg = Ikev2Configurator::genIkev2Config(connData);
|
||||
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg);
|
||||
QString cfg = m_configurator->ikev2Configurator->genIkev2Config(connData);
|
||||
cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg);
|
||||
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString();
|
||||
|
||||
set_textEditShareIkev2CertText(cfg);
|
||||
|
||||
QString mobileCfg = Ikev2Configurator::genMobileConfig(connData);
|
||||
QString mobileCfg = m_configurator->ikev2Configurator->genMobileConfig(connData);
|
||||
set_textEditShareIkev2MobileConfigText(mobileCfg);
|
||||
|
||||
QString strongSwanCfg = Ikev2Configurator::genStrongSwanConfig(connData);
|
||||
QString strongSwanCfg = m_configurator->ikev2Configurator->genStrongSwanConfig(connData);
|
||||
set_textEditShareIkev2StrongSwanConfigText(strongSwanCfg);
|
||||
|
||||
}
|
||||
|
@ -268,7 +270,7 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, DockerContainer co
|
|||
|
||||
QList<QString> ShareConnectionLogic::genQrCodeImageSeries(const QByteArray &data)
|
||||
{
|
||||
double k = 1500;
|
||||
double k = 850;
|
||||
|
||||
quint8 chunksCount = std::ceil(data.size() / k);
|
||||
QList<QString> chunks;
|
||||
|
@ -279,18 +281,15 @@ QList<QString> ShareConnectionLogic::genQrCodeImageSeries(const QByteArray &data
|
|||
|
||||
QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
|
||||
QImage qr = QZXing::encodeData(ba, QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L);
|
||||
chunks.append(imageToBase64(qr));
|
||||
QrCode qr = QrCode::encodeText(ba, QrCode::Ecc::LOW);
|
||||
QString svg = QString::fromStdString(toSvgString(qr, 0));
|
||||
chunks.append(svgToBase64(svg));
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
QString ShareConnectionLogic::imageToBase64(const QImage &image)
|
||||
QString ShareConnectionLogic::svgToBase64(const QString &image)
|
||||
{
|
||||
QByteArray ba;
|
||||
QBuffer bu(&ba);
|
||||
bu.open(QIODevice::WriteOnly);
|
||||
image.save(&bu, "PNG");
|
||||
return "data:image/png;base64," + QString::fromLatin1(ba.toBase64().data());
|
||||
return "data:image/svg;base64," + QString::fromLatin1(image.toUtf8().toBase64().data());
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SHARE_CONNECTION_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
@ -48,8 +49,7 @@ public:
|
|||
void updateSharingPage(int serverIndex, DockerContainer container);
|
||||
QList<QString> genQrCodeImageSeries(const QByteArray &data);
|
||||
|
||||
QString imageToBase64(const QImage &image);
|
||||
|
||||
QString svgToBase64(const QString &image);
|
||||
|
||||
};
|
||||
#endif // SHARE_CONNECTION_LOGIC_H
|
||||
|
|
|
@ -18,13 +18,13 @@ SitesLogic::SitesLogic(UiLogic *logic, QObject *parent):
|
|||
m_tableViewSitesModel{nullptr},
|
||||
m_lineEditSitesAddCustomText{}
|
||||
{
|
||||
sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(Settings::VpnOnlyForwardSites));
|
||||
sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites));
|
||||
sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(m_settings, Settings::VpnOnlyForwardSites));
|
||||
sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(m_settings, Settings::VpnAllExceptSites));
|
||||
}
|
||||
|
||||
void SitesLogic::onUpdatePage()
|
||||
{
|
||||
Settings::RouteMode m = m_settings.routeMode();
|
||||
Settings::RouteMode m = m_settings->routeMode();
|
||||
if (m == Settings::VpnAllSites) return;
|
||||
|
||||
if (m == Settings::VpnOnlyForwardSites) {
|
||||
|
@ -40,10 +40,10 @@ void SitesLogic::onUpdatePage()
|
|||
|
||||
void SitesLogic::onPushButtonAddCustomSitesClicked()
|
||||
{
|
||||
if (uiLogic()->vpnLogic()->radioButtonVpnModeAllSitesChecked()) {
|
||||
if (uiLogic()->pageLogic<VpnLogic>()->radioButtonVpnModeAllSitesChecked()) {
|
||||
return;
|
||||
}
|
||||
Settings::RouteMode mode = m_settings.routeMode();
|
||||
Settings::RouteMode mode = m_settings->routeMode();
|
||||
|
||||
QString newSite = lineEditSitesAddCustomText();
|
||||
|
||||
|
@ -60,7 +60,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
|
|||
}
|
||||
|
||||
const auto &cbProcess = [this, mode](const QString &newSite, const QString &ip) {
|
||||
m_settings.addVpnSite(mode, newSite, ip);
|
||||
m_settings->addVpnSite(mode, newSite, ip);
|
||||
|
||||
if (!ip.isEmpty()) {
|
||||
uiLogic()->m_vpnConnection->addRoutes(QStringList() << ip);
|
||||
|
@ -100,7 +100,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
|
|||
|
||||
void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items)
|
||||
{
|
||||
Settings::RouteMode mode = m_settings.routeMode();
|
||||
Settings::RouteMode mode = m_settings->routeMode();
|
||||
|
||||
auto siteModel = qobject_cast<SitesModel*> (tableViewSitesModel());
|
||||
if (!siteModel || items.isEmpty()) {
|
||||
|
@ -121,7 +121,7 @@ void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items)
|
|||
}
|
||||
}
|
||||
|
||||
m_settings.removeVpnSites(mode, sites);
|
||||
m_settings->removeVpnSites(mode, sites);
|
||||
|
||||
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
|
||||
uiLogic()->m_vpnConnection->deleteRoutes(ips);
|
||||
|
@ -139,7 +139,7 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
|
|||
return;
|
||||
}
|
||||
|
||||
Settings::RouteMode mode = m_settings.routeMode();
|
||||
Settings::RouteMode mode = m_settings->routeMode();
|
||||
|
||||
QStringList ips;
|
||||
QMap<QString, QString> sites;
|
||||
|
@ -187,8 +187,8 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
|
|||
|
||||
}
|
||||
|
||||
m_settings.addVpnIps(mode, ips);
|
||||
m_settings.addVpnSites(mode, sites);
|
||||
m_settings->addVpnIps(mode, ips);
|
||||
m_settings->addVpnSites(mode, sites);
|
||||
|
||||
uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips);
|
||||
uiLogic()->m_vpnConnection->flushDns();
|
||||
|
@ -198,9 +198,9 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
|
|||
|
||||
void SitesLogic::onPushButtonSitesExportClicked()
|
||||
{
|
||||
Settings::RouteMode mode = m_settings.routeMode();
|
||||
Settings::RouteMode mode = m_settings->routeMode();
|
||||
|
||||
QVariantMap sites = m_settings.vpnSites(mode);
|
||||
QVariantMap sites = m_settings->vpnSites(mode);
|
||||
|
||||
QString data;
|
||||
for (auto s : sites.keys()) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SITES_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
#include "settings.h"
|
||||
|
||||
class UiLogic;
|
||||
class SitesModel;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "StartPageLogic.h"
|
||||
#include "ViewConfigLogic.h"
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#include "configurators/ssh_configurator.h"
|
||||
#include "configurators/vpn_configurator.h"
|
||||
#include "../uilogic.h"
|
||||
#include "utilities.h"
|
||||
|
||||
|
@ -8,6 +11,7 @@
|
|||
#include <QStandardPaths>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QtAndroid>
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
|
@ -16,18 +20,20 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
|
|||
m_pushButtonConnectEnabled{true},
|
||||
m_pushButtonConnectText{tr("Connect")},
|
||||
m_pushButtonConnectKeyChecked{false},
|
||||
m_lineEditStartExistingCodeText{},
|
||||
m_textEditSshKeyText{},
|
||||
m_lineEditIpText{},
|
||||
m_lineEditPasswordText{},
|
||||
m_lineEditLoginText{},
|
||||
m_labelWaitInfoVisible{true},
|
||||
m_labelWaitInfoText{},
|
||||
m_pushButtonBackFromStartVisible{true},
|
||||
m_pushButtonConnectVisible{true},
|
||||
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
|
||||
{
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Set security screen for Android app
|
||||
QtAndroid::runOnAndroidThread([]() {
|
||||
QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;");
|
||||
if (window.isValid()){
|
||||
const int FLAG_SECURE = 8192;
|
||||
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void StartPageLogic::onUpdatePage()
|
||||
|
@ -41,7 +47,6 @@ void StartPageLogic::onUpdatePage()
|
|||
|
||||
set_labelWaitInfoVisible(false);
|
||||
set_labelWaitInfoText("");
|
||||
set_pushButtonConnectVisible(true);
|
||||
|
||||
set_pushButtonConnectKeyChecked(false);
|
||||
|
||||
|
@ -50,8 +55,6 @@ void StartPageLogic::onUpdatePage()
|
|||
|
||||
void StartPageLogic::onPushButtonConnect()
|
||||
{
|
||||
// uiLogic()->goToPage(Page::NewServer);
|
||||
// return;
|
||||
if (pushButtonConnectKeyChecked()){
|
||||
if (lineEditIpText().isEmpty() ||
|
||||
lineEditLoginText().isEmpty() ||
|
||||
|
@ -68,7 +71,6 @@ void StartPageLogic::onPushButtonConnect()
|
|||
return;
|
||||
}
|
||||
}
|
||||
qDebug() << "UiLogic::onPushButtonConnect checking new server";
|
||||
|
||||
ServerCredentials serverCredentials;
|
||||
serverCredentials.hostName = lineEditIpText();
|
||||
|
@ -85,7 +87,7 @@ void StartPageLogic::onPushButtonConnect()
|
|||
}
|
||||
|
||||
if (key.contains("OPENSSH") && key.contains("BEGIN") && key.contains("PRIVATE KEY")) {
|
||||
key = SshConfigurator::convertOpenSShKey(key);
|
||||
key = m_configurator->sshConfigurator->convertOpenSShKey(key);
|
||||
}
|
||||
|
||||
serverCredentials.password = key;
|
||||
|
@ -99,7 +101,7 @@ void StartPageLogic::onPushButtonConnect()
|
|||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
#ifdef Q_DEBUG
|
||||
//QString output = ServerController::checkSshConnection(serverCredentials, &e);
|
||||
//QString output = m_serverController->checkSshConnection(serverCredentials, &e);
|
||||
#else
|
||||
QString output;
|
||||
#endif
|
||||
|
@ -153,19 +155,10 @@ bool StartPageLogic::importConnection(const QJsonObject &profile)
|
|||
credentials.userName = profile.value(config_key::userName).toString();
|
||||
credentials.password = profile.value(config_key::password).toString();
|
||||
|
||||
// qDebug() << QString("Added server %3@%1:%2").
|
||||
// arg(credentials.hostName).
|
||||
// arg(credentials.port).
|
||||
// arg(credentials.userName);
|
||||
|
||||
//qDebug() << QString("Password") << credentials.password;
|
||||
|
||||
if (credentials.isValid() || profile.contains(config_key::containers)) {
|
||||
m_settings.addServer(profile);
|
||||
m_settings.setDefaultServer(m_settings.serversCount() - 1);
|
||||
|
||||
emit uiLogic()->goToPage(Page::Vpn);
|
||||
emit uiLogic()->setStartPage(Page::Vpn);
|
||||
// check config
|
||||
uiLogic()->pageLogic<ViewConfigLogic>()->set_configJson(profile);
|
||||
emit uiLogic()->goToPage(Page::ViewConfig);
|
||||
}
|
||||
else {
|
||||
qDebug() << "Failed to import profile";
|
||||
|
@ -174,8 +167,8 @@ bool StartPageLogic::importConnection(const QJsonObject &profile)
|
|||
}
|
||||
|
||||
if (!profile.contains(config_key::containers)) {
|
||||
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex);
|
||||
uiLogic()->selectedServerIndex = m_settings->defaultServerIndex();
|
||||
uiLogic()->selectedDockerContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex);
|
||||
uiLogic()->onUpdateAllPages();
|
||||
|
||||
emit uiLogic()->goToPage(Page::ServerContainers);
|
||||
|
@ -209,7 +202,6 @@ bool StartPageLogic::importConnectionFromCode(QString code)
|
|||
|
||||
bool StartPageLogic::importConnectionFromQr(const QByteArray &data)
|
||||
{
|
||||
qDebug() << "StartPageLogic::importConnectionFromQr" << data;
|
||||
QJsonObject dataObj = QJsonDocument::fromJson(data).object();
|
||||
if (!dataObj.isEmpty()) {
|
||||
return importConnection(dataObj);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "PageLogicBase.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
@ -22,7 +22,6 @@ class StartPageLogic : public PageLogicBase
|
|||
AUTO_PROPERTY(bool, labelWaitInfoVisible)
|
||||
AUTO_PROPERTY(QString, labelWaitInfoText)
|
||||
AUTO_PROPERTY(bool, pushButtonBackFromStartVisible)
|
||||
AUTO_PROPERTY(bool, pushButtonConnectVisible)
|
||||
|
||||
READONLY_PROPERTY(QRegularExpression, ipAddressPortRegex)
|
||||
public:
|
||||
|
|
67
client/ui/pages_logic/ViewConfigLogic.cpp
Normal file
67
client/ui/pages_logic/ViewConfigLogic.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "ViewConfigLogic.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "../uilogic.h"
|
||||
|
||||
|
||||
ViewConfigLogic::ViewConfigLogic(UiLogic *logic, QObject *parent):
|
||||
PageLogicBase(logic, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ViewConfigLogic::onUpdatePage()
|
||||
{
|
||||
set_configText(QJsonDocument(configJson()).toJson());
|
||||
|
||||
m_openVpnLastConfigs = m_openVpnMalStrings =
|
||||
"<style> \
|
||||
div { line-height: 0.5; } \
|
||||
</style><div>";
|
||||
|
||||
m_warningStringNumber = 3;
|
||||
m_warningActive = false;
|
||||
|
||||
const QJsonArray &containers = configJson()[config_key::containers].toArray();
|
||||
int i = 0;
|
||||
for (const QJsonValue &v: containers) {
|
||||
QString cfg_json = v.toObject()[ProtocolProps::protoToString(Proto::OpenVpn)]
|
||||
.toObject()[config_key::last_config].toString();
|
||||
|
||||
QString openvpn_cfg = QJsonDocument::fromJson(cfg_json.toUtf8()).object()[config_key::config]
|
||||
.toString();
|
||||
|
||||
openvpn_cfg.replace("\r", "");
|
||||
|
||||
QStringList lines = openvpn_cfg.split("\n");
|
||||
for (const QString &l: lines) {
|
||||
i++;
|
||||
QRegularExpressionMatch match = m_re.match(l);
|
||||
if (dangerousTags.contains(match.captured(0))) {
|
||||
QString t = QString("<p><font color=\"red\">%1</font>").arg(l);
|
||||
m_openVpnLastConfigs.append(t + "\n");
|
||||
m_openVpnMalStrings.append(t);
|
||||
if (m_warningStringNumber == 3) m_warningStringNumber = i - 3;
|
||||
m_warningActive = true;
|
||||
qDebug() << "ViewConfigLogic : malicious scripts warning:" << l;
|
||||
}
|
||||
else {
|
||||
m_openVpnLastConfigs.append("<p>" + l + " \n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit openVpnLastConfigsChanged(m_openVpnLastConfigs);
|
||||
emit openVpnMalStringsChanged(m_openVpnMalStrings);
|
||||
emit warningStringNumberChanged(m_warningStringNumber);
|
||||
emit warningActiveChanged(m_warningActive);
|
||||
}
|
||||
|
||||
void ViewConfigLogic::importConfig()
|
||||
{
|
||||
m_settings->addServer(configJson());
|
||||
m_settings->setDefaultServer(m_settings->serversCount() - 1);
|
||||
|
||||
emit uiLogic()->goToPage(Page::Vpn);
|
||||
emit uiLogic()->setStartPage(Page::Vpn);
|
||||
}
|
||||
|
47
client/ui/pages_logic/ViewConfigLogic.h
Normal file
47
client/ui/pages_logic/ViewConfigLogic.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef VIEW_CONFIG_LOGIC_H
|
||||
#define VIEW_CONFIG_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
class UiLogic;
|
||||
|
||||
class ViewConfigLogic : public PageLogicBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
AUTO_PROPERTY(QString, configText)
|
||||
AUTO_PROPERTY(QString, openVpnLastConfigs)
|
||||
AUTO_PROPERTY(QString, openVpnMalStrings)
|
||||
AUTO_PROPERTY(QJsonObject, configJson)
|
||||
AUTO_PROPERTY(int, warningStringNumber)
|
||||
AUTO_PROPERTY(bool, warningActive)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void onUpdatePage() override;
|
||||
Q_INVOKABLE void importConfig();
|
||||
|
||||
|
||||
public:
|
||||
explicit ViewConfigLogic(UiLogic *uiLogic, QObject *parent = nullptr);
|
||||
~ViewConfigLogic() = default;
|
||||
|
||||
private:
|
||||
QRegularExpression m_re {"(\\w+-\\w+|\\w+)"};
|
||||
|
||||
// https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst
|
||||
QStringList dangerousTags {
|
||||
"up",
|
||||
"tls-verify",
|
||||
"ipchange",
|
||||
"client-connect",
|
||||
"route-up",
|
||||
"route-pre-down",
|
||||
"client-disconnect",
|
||||
"down",
|
||||
"learn-address",
|
||||
"auth-user-pass-verify"
|
||||
};
|
||||
};
|
||||
#endif // VIEW_CONFIG_LOGIC_H
|
|
@ -33,7 +33,7 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
|
|||
connect(this, &VpnLogic::connectToVpn, uiLogic()->m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection);
|
||||
connect(this, &VpnLogic::disconnectFromVpn, uiLogic()->m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
|
||||
|
||||
if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) {
|
||||
if (m_settings->isAutoConnect() && m_settings->defaultServerIndex() >= 0) {
|
||||
QTimer::singleShot(1000, this, [this](){
|
||||
set_pushButtonConnectEnabled(false);
|
||||
onConnect();
|
||||
|
@ -47,20 +47,20 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
|
|||
|
||||
void VpnLogic::onUpdatePage()
|
||||
{
|
||||
Settings::RouteMode mode = m_settings.routeMode();
|
||||
DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
|
||||
Settings::RouteMode mode = m_settings->routeMode();
|
||||
DockerContainer selectedContainer = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||
|
||||
set_isCustomRoutesSupported (selectedContainer == DockerContainer::OpenVpn ||
|
||||
selectedContainer == DockerContainer::ShadowSocks||
|
||||
selectedContainer == DockerContainer::Cloak);
|
||||
|
||||
set_isContainerHaveAuthData(m_settings.haveAuthData(m_settings.defaultServerIndex()));
|
||||
set_isContainerHaveAuthData(m_settings->haveAuthData(m_settings->defaultServerIndex()));
|
||||
|
||||
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites || !isCustomRoutesSupported());
|
||||
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites && isCustomRoutesSupported());
|
||||
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites && isCustomRoutesSupported());
|
||||
|
||||
const QJsonObject &server = uiLogic()->m_settings.defaultServer();
|
||||
const QJsonObject &server = uiLogic()->m_settings->defaultServer();
|
||||
QString serverString = QString("%2 (%3)")
|
||||
.arg(server.value(config_key::description).toString())
|
||||
.arg(server.value(config_key::hostName).toString());
|
||||
|
@ -69,7 +69,7 @@ void VpnLogic::onUpdatePage()
|
|||
QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer);
|
||||
set_labelCurrentService(selectedContainerName);
|
||||
|
||||
auto dns = VpnConfigurator::getDnsForConfig(m_settings.defaultServerIndex());
|
||||
auto dns = m_configurator->getDnsForConfig(m_settings->defaultServerIndex());
|
||||
set_amneziaDnsEnabled(dns.first == protocols::dns::amneziaDnsIp);
|
||||
if (dns.first == protocols::dns::amneziaDnsIp) {
|
||||
set_labelCurrentDns("On your server");
|
||||
|
@ -93,19 +93,19 @@ void VpnLogic::onUpdatePage()
|
|||
|
||||
void VpnLogic::onRadioButtonVpnModeAllSitesClicked()
|
||||
{
|
||||
m_settings.setRouteMode(Settings::VpnAllSites);
|
||||
m_settings->setRouteMode(Settings::VpnAllSites);
|
||||
onUpdatePage();
|
||||
}
|
||||
|
||||
void VpnLogic::onRadioButtonVpnModeForwardSitesClicked()
|
||||
{
|
||||
m_settings.setRouteMode(Settings::VpnOnlyForwardSites);
|
||||
m_settings->setRouteMode(Settings::VpnOnlyForwardSites);
|
||||
onUpdatePage();
|
||||
}
|
||||
|
||||
void VpnLogic::onRadioButtonVpnModeExceptSitesClicked()
|
||||
{
|
||||
m_settings.setRouteMode(Settings::VpnAllExceptSites);
|
||||
m_settings->setRouteMode(Settings::VpnAllExceptSites);
|
||||
onUpdatePage();
|
||||
}
|
||||
|
||||
|
@ -203,11 +203,11 @@ void VpnLogic::onPushButtonConnectClicked()
|
|||
|
||||
void VpnLogic::onConnect()
|
||||
{
|
||||
int serverIndex = m_settings.defaultServerIndex();
|
||||
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
|
||||
DockerContainer container = m_settings.defaultContainer(serverIndex);
|
||||
int serverIndex = m_settings->defaultServerIndex();
|
||||
ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
|
||||
DockerContainer container = m_settings->defaultContainer(serverIndex);
|
||||
|
||||
if (m_settings.containers(serverIndex).isEmpty()) {
|
||||
if (m_settings->containers(serverIndex).isEmpty()) {
|
||||
set_labelErrorText(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
|
||||
set_pushButtonConnectChecked(false);
|
||||
return;
|
||||
|
@ -220,7 +220,7 @@ void VpnLogic::onConnect()
|
|||
}
|
||||
|
||||
|
||||
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
|
||||
const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
|
||||
onConnectWorker(serverIndex, credentials, container, containerConfig);
|
||||
}
|
||||
|
||||
|
@ -233,14 +233,6 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent
|
|||
qApp->processEvents();
|
||||
|
||||
emit connectToVpn(serverIndex, credentials, container, containerConfig);
|
||||
|
||||
// if (errorCode) {
|
||||
// //ui->pushButton_connect->setChecked(false);
|
||||
// uiLogic()->setDialogConnectErrorText(errorString(errorCode));
|
||||
// emit uiLogic()->showConnectErrorDialog();
|
||||
// return;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void VpnLogic::onDisconnect()
|
||||
|
|
|
@ -55,9 +55,9 @@ void WizardLogic::onPushButtonVpnModeFinishClicked()
|
|||
auto containers = getInstallConfigsFromWizardPage();
|
||||
uiLogic()->installServer(containers);
|
||||
if (checkBoxVpnModeChecked()) {
|
||||
m_settings.setRouteMode(Settings::VpnOnlyForwardSites);
|
||||
m_settings->setRouteMode(Settings::VpnOnlyForwardSites);
|
||||
} else {
|
||||
m_settings.setRouteMode(Settings::VpnAllSites);
|
||||
m_settings->setRouteMode(Settings::VpnAllSites);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define WIZARD_LOGIC_H
|
||||
|
||||
#include "PageLogicBase.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
class UiLogic;
|
||||
|
||||
|
|
|
@ -52,10 +52,10 @@ QJsonObject CloakLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
|
|||
|
||||
void CloakLogic::onPushButtonSaveClicked()
|
||||
{
|
||||
QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::Cloak);
|
||||
QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::Cloak);
|
||||
protocolConfig = getProtocolConfigFromPage(protocolConfig);
|
||||
|
||||
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
QJsonObject newContainerConfig = containerConfig;
|
||||
newContainerConfig.insert(ProtocolProps::protoToString(Proto::Cloak), protocolConfig);
|
||||
|
||||
|
@ -89,14 +89,14 @@ void CloakLogic::onPushButtonSaveClicked()
|
|||
};
|
||||
|
||||
ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){
|
||||
return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig);
|
||||
return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig);
|
||||
},
|
||||
page_func, progressBar_reset,
|
||||
pushButton_save_func, label_info_func);
|
||||
|
||||
if (!e) {
|
||||
m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig);
|
||||
m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig);
|
||||
m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
|
||||
}
|
||||
|
||||
qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->selectedServerIndex << uiLogic()->selectedDockerContainer;
|
||||
|
|
|
@ -32,7 +32,6 @@ public:
|
|||
QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override;
|
||||
|
||||
private:
|
||||
Settings m_settings;
|
||||
UiLogic *m_uiLogic;
|
||||
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue