Major change to the build system and minor changes to SSL handling
- mutiple SSL cert files can now be added to the MRCI_PUB_KEY env variable via colon seperated ':' path strings to complete the cert chain if such a thing is required. It is no longer necessary to merge to multiple certs into one to complete a cert chain. - added -load_ssl command line option so cert data can be re-loaded in real time without the need to stop-start the host. - added more detailed error messages to the SSL loading process for easier debugging. - major changes to the build system include the use of python scripts instead of the linux shell script file. - linux_build.sh was removed since it is no longer needed. - the new build process now run 2 python scripts: build.py and then install.py. - the resulting installer if built no longer uses makeself. the installation and/or self extracting process is now handled entirely by python and the install.py script. The main reason for this change is to lay the ground work for multi- platform support. It is still linux only for now but adding windows support will be much easier in the future thanks to python's cross- platform support.
This commit is contained in:
parent
80d493ad16
commit
48b4c5b537
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -28,6 +28,8 @@ ui_*.h
|
||||||
*.jsc
|
*.jsc
|
||||||
Makefile*
|
Makefile*
|
||||||
*build-*
|
*build-*
|
||||||
|
/build
|
||||||
|
/app_dir
|
||||||
|
|
||||||
# Qt unit tests
|
# Qt unit tests
|
||||||
target_wrapper.*
|
target_wrapper.*
|
||||||
|
|
5
MRCI.pro
5
MRCI.pro
|
@ -27,7 +27,10 @@ QT += sql
|
||||||
CONFIG += console
|
CONFIG += console
|
||||||
CONFIG -= app_bundle
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
TARGET = mrci
|
TARGET = build/mrci
|
||||||
|
OBJECTS_DIR = build
|
||||||
|
MOC_DIR = build
|
||||||
|
RCC_DIR = build
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
|
|
||||||
|
|
186
build.py
Normal file
186
build.py
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
#!/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def get_app_target(text):
|
||||||
|
return re.search(r'(APP_TARGET) +(\"(.*?)\")', text).group(3)
|
||||||
|
|
||||||
|
def get_app_ver(text):
|
||||||
|
return re.search(r'(APP_VER) +(\"(.*?)\")', text).group(3)
|
||||||
|
|
||||||
|
def get_app_name(text):
|
||||||
|
return re.search(r'(APP_NAME) +(\"(.*?)\")', text).group(3)
|
||||||
|
|
||||||
|
def get_qt_path():
|
||||||
|
try:
|
||||||
|
return str(subprocess.check_output(["qtpaths", "--binaries-dir"]), 'utf-8').strip()
|
||||||
|
|
||||||
|
except CalledProcessError:
|
||||||
|
print("A call to 'qtpaths' to get the QT installation bin folder failed.")
|
||||||
|
|
||||||
|
return raw_input("Please enter the QT bin path (leave blank to cancel the build): ")
|
||||||
|
|
||||||
|
def get_qt_from_cli():
|
||||||
|
for arg in sys.argv:
|
||||||
|
if arg == "-qt_dir":
|
||||||
|
index = sys.argv.index(arg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return sys.argv[index + 1]
|
||||||
|
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_db_header():
|
||||||
|
current_dir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
if current_dir == "":
|
||||||
|
return "src" + os.sep + "db.h"
|
||||||
|
else:
|
||||||
|
return current_dir + os.sep + "src" + os.sep + "db.h"
|
||||||
|
|
||||||
|
def cd():
|
||||||
|
current_dir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
if current_dir != "":
|
||||||
|
os.chdir(current_dir)
|
||||||
|
|
||||||
|
def verbose_copy(src, dst):
|
||||||
|
print("cpy: " + src + " --> " + dst)
|
||||||
|
|
||||||
|
if os.path.isdir(src):
|
||||||
|
if os.path.exists(dst) and os.path.isdir(dst):
|
||||||
|
shutil.rmtree(dst)
|
||||||
|
|
||||||
|
shutil.copytree(src, dst)
|
||||||
|
|
||||||
|
else:
|
||||||
|
shutil.copyfile(src, dst)
|
||||||
|
|
||||||
|
def linux_build_app_dir(app_ver, app_name, app_target, qt_bin):
|
||||||
|
if not os.path.exists("app_dir/linux/sqldrivers"):
|
||||||
|
os.makedirs("app_dir/linux/sqldrivers")
|
||||||
|
|
||||||
|
if not os.path.exists("app_dir/linux/lib"):
|
||||||
|
os.makedirs("app_dir/linux/lib")
|
||||||
|
|
||||||
|
verbose_copy(qt_bin + "/../plugins/sqldrivers/libqsqlite.so", "app_dir/linux/sqldrivers/libqsqlite.so")
|
||||||
|
verbose_copy("build/" + app_target, "app_dir/linux/" + app_target)
|
||||||
|
|
||||||
|
shutil.copyfile("build/" + app_target, "/tmp/" + app_target)
|
||||||
|
# copying the executable file from the build folder to
|
||||||
|
# temp bypasses any -noexe retrictions a linux file
|
||||||
|
# system may have. there is a chance temp is also
|
||||||
|
# restricted in this way but that kind of config is
|
||||||
|
# rare. ldd will not run correctly with -noexe
|
||||||
|
# enabled.
|
||||||
|
|
||||||
|
lines = str(subprocess.check_output(["ldd", "/tmp/" + app_target]), 'utf-8').split("\n")
|
||||||
|
|
||||||
|
os.remove("/tmp/" + app_target)
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if " => " in line:
|
||||||
|
if ("libQt" in line) or ("libicu" in line) or ("libssl" in line) or ("libcrypto" in line):
|
||||||
|
if " (0x0" in line:
|
||||||
|
start_index = line.index("> ") + 2
|
||||||
|
end_index = line.index(" (0x0")
|
||||||
|
src_file = line[start_index:end_index]
|
||||||
|
file_name = os.path.basename(src_file)
|
||||||
|
|
||||||
|
verbose_copy(src_file, "app_dir/linux/lib/" + file_name)
|
||||||
|
|
||||||
|
with open("app_dir/linux/" + app_target + ".sh", "w") as file:
|
||||||
|
file.write("#!/bin/sh\n")
|
||||||
|
file.write("export QTDIR=$install_dir\n")
|
||||||
|
file.write("export QT_PLUGIN_PATH=$install_dir\n")
|
||||||
|
file.write("export LD_LIBRARY_PATH=\"$install_dir/lib:\$LD_LIBRARY_PATH\"\n")
|
||||||
|
file.write("$install_dir/" + app_target + " $1 $2 $3\n")
|
||||||
|
|
||||||
|
with open("app_dir/linux/" + app_target + ".service", "w") as file:
|
||||||
|
file.write("[Unit]\n")
|
||||||
|
file.write("Description=" + app_name + " Host Daemon\n")
|
||||||
|
file.write("After=network.target\n\n")
|
||||||
|
file.write("[Service]\n")
|
||||||
|
file.write("Type=simple\n")
|
||||||
|
file.write("User=" + app_target + "\n")
|
||||||
|
file.write("Restart=on-failure\n")
|
||||||
|
file.write("RestartSec=5\n")
|
||||||
|
file.write("TimeoutStopSec=infinity\n")
|
||||||
|
file.write("ExecStart=/usr/bin/env " + app_target + " -host\n")
|
||||||
|
file.write("ExecStop=/usr/bin/env " + app_target + " -stop\n\n")
|
||||||
|
file.write("[Install]\n")
|
||||||
|
file.write("WantedBy=multi-user.target\n")
|
||||||
|
|
||||||
|
with open("app_dir/linux/uninstall.sh", "w") as file:
|
||||||
|
file.write("#!/bin/sh\n")
|
||||||
|
file.write("systemctl -q stop " + app_target + "\n")
|
||||||
|
file.write("systemctl -q disable " + app_target + "\n")
|
||||||
|
file.write("rm -v /etc/systemd/system/" + app_target + ".service\n")
|
||||||
|
file.write("rm -v /usr/bin/" + app_target + "\n")
|
||||||
|
file.write("rm -rv $install_dir\n")
|
||||||
|
file.write("deluser " + app_target + "\n")
|
||||||
|
|
||||||
|
complete(app_ver)
|
||||||
|
|
||||||
|
def windows_build_app_dir():
|
||||||
|
print("Windows support is work in progress. Check for an update at a later time.")
|
||||||
|
# to do: fill out code for windows support here.
|
||||||
|
|
||||||
|
def complete(app_ver):
|
||||||
|
print("Build complete for version: " + app_ver)
|
||||||
|
print("You can now run the install.py script to install onto this machine or create an installer.")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(get_db_header()) as file:
|
||||||
|
text = file.read()
|
||||||
|
|
||||||
|
app_target = get_app_target(text)
|
||||||
|
app_ver = get_app_ver(text)
|
||||||
|
app_name = get_app_name(text)
|
||||||
|
qt_bin = get_qt_from_cli()
|
||||||
|
|
||||||
|
if qt_bin is "":
|
||||||
|
qt_bin = get_qt_path()
|
||||||
|
|
||||||
|
if qt_bin != "":
|
||||||
|
print("app_target = " + app_target)
|
||||||
|
print("app_version = " + app_ver)
|
||||||
|
print("app_name = " + app_name)
|
||||||
|
print("qt_bin = " + qt_bin)
|
||||||
|
|
||||||
|
cd()
|
||||||
|
|
||||||
|
result = subprocess.run([qt_bin + os.sep + "qmake", "-config", "release"])
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
result = subprocess.run(["make"])
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
if not os.path.exists("app_dir"):
|
||||||
|
os.makedirs("app_dir")
|
||||||
|
|
||||||
|
with open("app_dir" + os.sep + "info.txt", "w") as info_file:
|
||||||
|
info_file.write(app_target + "\n")
|
||||||
|
info_file.write(app_ver + "\n")
|
||||||
|
info_file.write(app_name + "\n")
|
||||||
|
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
linux_build_app_dir(app_ver, app_name, app_target, qt_bin)
|
||||||
|
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
windows_build_app_dir()
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("The platform you are running in is not compatible with the app_dir build out procedure.")
|
||||||
|
print(" output from platform.system() = " + platform.system())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -5,6 +5,8 @@
|
||||||
### Usage ###
|
### Usage ###
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Usage: mrci <argument>
|
||||||
|
|
||||||
<Arguments>
|
<Arguments>
|
||||||
|
|
||||||
-help : display usage information about this application.
|
-help : display usage information about this application.
|
||||||
|
@ -19,8 +21,7 @@
|
||||||
-exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only.
|
-exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only.
|
||||||
-user_cmds : run the internal module to list it's user commands. for internal use only.
|
-user_cmds : run the internal module to list it's user commands. for internal use only.
|
||||||
-run_cmd : run an internal module command. for internal use only.
|
-run_cmd : run an internal module command. for internal use only.
|
||||||
-add_cert : add/update an SSL certificate for a given common name.
|
-load_ssl : re-load the host SSL certificate without stopping the host instance.
|
||||||
-rm_cert : remove an SSL certificate for a given common name.
|
|
||||||
|
|
||||||
Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:
|
Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ Any one user account registered with the host can be given root privileges which
|
||||||
|
|
||||||
### More Than Just a Command Interpreter ###
|
### More Than Just a Command Interpreter ###
|
||||||
|
|
||||||
Typical use for a MRCI host is to run commands that clients ask it to run, very similar to what you see in terminal emulators. It however does have a few feasures typically not seen in local terminals:
|
Typical use for a MRCI host is to run commands on a remote host that clients ask it to run, very similar to what you see in remote terminal emulators. It however does have a few feasures typically not seen in terminals:
|
||||||
|
|
||||||
* Broadcast any type of data to all peers connected to the host.
|
* Broadcast any type of data to all peers connected to the host.
|
||||||
* Run remote commands on connected peers.
|
* Run remote commands on connected peers.
|
||||||
|
@ -72,38 +73,41 @@ Because the host is modular, the things you can customize it to do is almost lim
|
||||||
* [6.1 Shared Memory](shared_data.md)
|
* [6.1 Shared Memory](shared_data.md)
|
||||||
* [7.1 Internal Commands](intern_commands.md)
|
* [7.1 Internal Commands](intern_commands.md)
|
||||||
|
|
||||||
### Development Setup ###
|
### Build Setup ###
|
||||||
|
|
||||||
Linux Required Packages:
|
For Linux you need the following packages to successfully build/install:
|
||||||
```
|
```
|
||||||
qtbase5-dev
|
qtbase5-dev
|
||||||
libssl-dev
|
libssl-dev
|
||||||
gcc
|
gcc
|
||||||
make
|
make
|
||||||
makeself
|
python3
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build From Source (Linux) ###
|
Windows support is still work in progress but the following applications will must likely need to be installed:
|
||||||
|
|
||||||
Linux_build.sh is a custom script designed to build this project from the source code using qmake, make and makeself. You can pass 2 optional arguments:
|
|
||||||
|
|
||||||
1. The path to the QT bin folder in case you want to compile with a QT install not defined in PATH.
|
|
||||||
2. Path of the output makeself file (usually has a .run extension). If not given, the outfile will be named mrci-x.x.x.run in the source code folder.
|
|
||||||
|
|
||||||
Build:
|
|
||||||
```
|
```
|
||||||
cd /path/to/source/code
|
OpenSSL
|
||||||
sh ./linux_build.sh
|
Qt5.12 or newer
|
||||||
```
|
Python3
|
||||||
Install:
|
|
||||||
```
|
|
||||||
chmod +x ./mrci-x.x.x.run
|
|
||||||
./mrci-x.x.x.run
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The makeself installer not only installs the application but also installs it as a service if the target linux system supports systemd.
|
### Build ###
|
||||||
|
|
||||||
Start/Stop the service:
|
To build this project from source you just need to run the build.py and then the install.py python scripts. While running the build the script, it will try to find the Qt API installed in your machine according to the PATH env variable. If not found, it will ask you to input where it can find the Qt bin folder where the qmake executable exists or you can bypass all of this by passing the -qt_dir option on it's command line.
|
||||||
|
|
||||||
|
while running the install script, it will ask you to input 1 of 3 options:
|
||||||
|
|
||||||
|
***local machine*** - This option will install the built application onto the local machine without creating an installer.
|
||||||
|
|
||||||
|
***create installer*** - This option creates an installer that can be distributed to other machines to installation. The resulting installer is just a regular .py script file that the target machine can run if it has Python3 insalled. Only Python3 needs to be installed and an internet connection is not required.
|
||||||
|
|
||||||
|
***exit*** - Cancel the installation.
|
||||||
|
|
||||||
|
-local or -installer can be passed as command line options for install.py to explicitly select one of the above options without pausing for user input.
|
||||||
|
|
||||||
|
### Services ###
|
||||||
|
|
||||||
|
If a target linux system supports systemd, the application will be installed as a background daemon that can start/stop with the following commands:
|
||||||
```
|
```
|
||||||
sudo systemctl start mrci
|
sudo systemctl start mrci
|
||||||
sudo systemctl stop mrci
|
sudo systemctl stop mrci
|
||||||
|
|
315
install.py
Normal file
315
install.py
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
#!/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
import binascii
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
def cd():
|
||||||
|
current_dir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
if current_dir != "":
|
||||||
|
os.chdir(current_dir)
|
||||||
|
|
||||||
|
def get_default_install_dir(app_target, app_name):
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
return "/opt/" + app_target
|
||||||
|
|
||||||
|
else:
|
||||||
|
return "C:\\Program Files\\" + app_name
|
||||||
|
|
||||||
|
def get_default_installer_path(app_ver, app_name):
|
||||||
|
return os.path.expanduser("~") + os.sep + app_name + "-" + app_ver + ".py"
|
||||||
|
|
||||||
|
def get_install_dir(app_target, app_name):
|
||||||
|
path = get_default_install_dir(app_target, app_name)
|
||||||
|
|
||||||
|
print("The default install directory is: " + path)
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
ans = input("Do you want to change it? (y/n): ")
|
||||||
|
|
||||||
|
if ans == "y" or ans == "Y":
|
||||||
|
path = input("Enter a new install directory (leave blank to go back to the default): ")
|
||||||
|
path = os.path.normpath(path)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif ans == "n" or ans == "N":
|
||||||
|
break
|
||||||
|
|
||||||
|
if path == "":
|
||||||
|
return get_default_install_dir(app_target, app_name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
def get_installer_path(app_ver, app_name):
|
||||||
|
path = get_default_installer_path(app_ver, app_name)
|
||||||
|
|
||||||
|
print("The built .py installer will placed here: " + path)
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
ans = input("Do you want to change the path? (y/n): ")
|
||||||
|
|
||||||
|
if ans == "y" or ans == "Y":
|
||||||
|
path = input("Enter a new path (leave blank to go back to the default): ")
|
||||||
|
path = os.path.normpath(path)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif ans == "n" or ans == "N":
|
||||||
|
break
|
||||||
|
|
||||||
|
if path == "":
|
||||||
|
return get_default_installer_path(app_ver, app_name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
def make_install_dir(path):
|
||||||
|
try:
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
except:
|
||||||
|
print("Failed to create the install directory, please make sure you are runnning this script with admin rights.")
|
||||||
|
|
||||||
|
def replace_text(text, old_text, new_text, offs):
|
||||||
|
while(True):
|
||||||
|
try:
|
||||||
|
index = text.index(old_text, offs)
|
||||||
|
text = text[:index] + new_text + text[index + len(old_text):]
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
break
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
def sub_copy_file(src, dst, old_text, new_text, offs):
|
||||||
|
print("cpy: " + src + " --> " + dst)
|
||||||
|
|
||||||
|
text = ""
|
||||||
|
|
||||||
|
with open(src, "r") as rd_file:
|
||||||
|
text = rd_file.read()
|
||||||
|
text = replace_text(text, old_text, new_text, offs)
|
||||||
|
|
||||||
|
with open(dst, "w") as wr_file:
|
||||||
|
wr_file.write(text)
|
||||||
|
|
||||||
|
def verbose_copy(src, dst):
|
||||||
|
print("cpy: " + src + " --> " + dst)
|
||||||
|
|
||||||
|
if os.path.isdir(src):
|
||||||
|
if os.path.exists(dst) and os.path.isdir(dst):
|
||||||
|
shutil.rmtree(dst)
|
||||||
|
|
||||||
|
shutil.copytree(src, dst)
|
||||||
|
|
||||||
|
else:
|
||||||
|
shutil.copyfile(src, dst)
|
||||||
|
|
||||||
|
def verbose_create_symmlink(src, dst):
|
||||||
|
print("lnk: " + src + " --> " + dst)
|
||||||
|
|
||||||
|
if os.path.exists(dst):
|
||||||
|
os.remove(dst)
|
||||||
|
|
||||||
|
os.symlink(src, dst)
|
||||||
|
|
||||||
|
def local_install(app_target, app_name):
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
if not os.path.exists("app_dir/linux"):
|
||||||
|
print("An app_dir for the Linux platform could not be found.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
install_dir = get_install_dir(app_target, app_name)
|
||||||
|
|
||||||
|
if os.path.exists(install_dir + "/uninstall.sh"):
|
||||||
|
subprocess.run([install_dir + "/uninstall.sh"])
|
||||||
|
|
||||||
|
make_install_dir(install_dir)
|
||||||
|
|
||||||
|
if not os.path.exists("/var/opt/" + app_target):
|
||||||
|
os.makedirs("/var/opt/" + app_target)
|
||||||
|
|
||||||
|
sub_copy_file("app_dir/linux/" + app_target + ".sh", install_dir + "/" + app_target + ".sh", "$install_dir", install_dir, 0)
|
||||||
|
sub_copy_file("app_dir/linux/uninstall.sh", install_dir + "/uninstall.sh", "$install_dir", install_dir, 0)
|
||||||
|
|
||||||
|
verbose_copy("app_dir/linux/" + app_target, install_dir + "/" + app_target)
|
||||||
|
verbose_copy("app_dir/linux/lib", install_dir + "/lib")
|
||||||
|
verbose_copy("app_dir/linux/sqldrivers", install_dir + "/sqldrivers")
|
||||||
|
verbose_copy("app_dir/linux/" + app_target + ".service", "/etc/systemd/system/" + app_target + ".service")
|
||||||
|
|
||||||
|
verbose_create_symmlink(install_dir + "/" + app_target + ".sh", "/usr/bin/" + app_target)
|
||||||
|
|
||||||
|
subprocess.run(["useradd", "-r", app_target])
|
||||||
|
subprocess.run(["chmod", "-R", "755", install_dir])
|
||||||
|
subprocess.run(["chmod", "755", "/etc/systemd/system/" + app_target + ".service"])
|
||||||
|
subprocess.run(["chown", "-R", app_target + ":" + app_target, "/var/opt/" + app_target])
|
||||||
|
subprocess.run(["systemctl", "start", app_target])
|
||||||
|
subprocess.run(["systemctl", "enable", app_target])
|
||||||
|
|
||||||
|
print("Installation finished. If you ever need to uninstall this application, run this command with root rights:")
|
||||||
|
print(" sh " + install_dir + "/uninstall.sh\n")
|
||||||
|
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
print("Windows support is work progress. Check for an update at a later time.")
|
||||||
|
# to do: fill ot code for windows support here.
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("The platform you are running in is not compatible.")
|
||||||
|
print(" output from platform.system() = " + platform.system())
|
||||||
|
|
||||||
|
def dir_tree(path):
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
if os.path.isdir(path):
|
||||||
|
for entry in os.listdir(path):
|
||||||
|
full_path = os.path.join(path, entry)
|
||||||
|
|
||||||
|
if os.path.isdir(full_path):
|
||||||
|
for sub_dir_file in dir_tree(full_path):
|
||||||
|
ret.append(sub_dir_file)
|
||||||
|
|
||||||
|
else:
|
||||||
|
ret.append(full_path)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def to_hex(data):
|
||||||
|
return str(binascii.hexlify(data))[2:-1]
|
||||||
|
|
||||||
|
def from_hex(text_line):
|
||||||
|
return binascii.unhexlify(text_line)
|
||||||
|
|
||||||
|
def make_install(app_ver, app_name):
|
||||||
|
path = get_installer_path(app_ver, app_name)
|
||||||
|
|
||||||
|
with zipfile.ZipFile("app_dir.zip", "w", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
||||||
|
print("Compressing app_dir --")
|
||||||
|
|
||||||
|
for file in dir_tree("app_dir"):
|
||||||
|
print("adding file: " + file)
|
||||||
|
zip_file.write(file)
|
||||||
|
|
||||||
|
sub_copy_file(__file__, path, "main(is_sfx=False)", "main(is_sfx=True)\n\n\n", 7700)
|
||||||
|
|
||||||
|
with open(path, "a") as dst_file, open("app_dir.zip", "rb") as src_file:
|
||||||
|
print("Packing the compressed app_dir into the sfx script file --")
|
||||||
|
|
||||||
|
dst_file.write("# APP_DIR\n")
|
||||||
|
|
||||||
|
stat = os.stat("app_dir.zip")
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
buffer = src_file.read(4000000)
|
||||||
|
|
||||||
|
if len(buffer) != 0:
|
||||||
|
dst_file.write("# " + to_hex(buffer) + "\n")
|
||||||
|
|
||||||
|
print(str(src_file.tell()) + "/" + str(stat.st_size))
|
||||||
|
|
||||||
|
if len(buffer) < 4000000:
|
||||||
|
break
|
||||||
|
|
||||||
|
os.remove("app_dir.zip")
|
||||||
|
|
||||||
|
print("Finished.")
|
||||||
|
|
||||||
|
def sfx():
|
||||||
|
abs_sfx_path = os.path.abspath(__file__)
|
||||||
|
mark_found = False
|
||||||
|
|
||||||
|
os.chdir(tempfile.gettempdir())
|
||||||
|
|
||||||
|
with open(abs_sfx_path) as packed_file, open("app_dir.zip", "wb") as zip_file:
|
||||||
|
stat = os.stat(abs_sfx_path)
|
||||||
|
|
||||||
|
print("Unpacking the app_dir compressed file from the sfx script.")
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
line = packed_file.readline()
|
||||||
|
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
|
||||||
|
elif mark_found:
|
||||||
|
zip_file.write(from_hex(line[2:-1]))
|
||||||
|
|
||||||
|
print(str(packed_file.tell()) + "/" + str(stat.st_size))
|
||||||
|
|
||||||
|
else:
|
||||||
|
if line == "# APP_DIR\n":
|
||||||
|
mark_found = True
|
||||||
|
|
||||||
|
print("Done.")
|
||||||
|
|
||||||
|
if not mark_found:
|
||||||
|
print("The app_dir mark was not found, unable to continue.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
with zipfile.ZipFile("app_dir.zip", "r", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
||||||
|
print("De-compressing app_dir --")
|
||||||
|
|
||||||
|
zip_file.extractall()
|
||||||
|
|
||||||
|
print("Preparing for installation.")
|
||||||
|
|
||||||
|
os.remove("app_dir.zip")
|
||||||
|
|
||||||
|
with open("app_dir" + os.sep + "info.txt") as info_file:
|
||||||
|
list = info_file.read().split("\n")
|
||||||
|
|
||||||
|
local_install(list[0], list[2])
|
||||||
|
shutil.rmtree("app_dir")
|
||||||
|
|
||||||
|
def main(is_sfx):
|
||||||
|
cd()
|
||||||
|
|
||||||
|
app_target = ""
|
||||||
|
app_ver = ""
|
||||||
|
app_name = ""
|
||||||
|
|
||||||
|
if not is_sfx:
|
||||||
|
with open("app_dir" + os.sep + "info.txt") as info_file:
|
||||||
|
list = info_file.read().split("\n")
|
||||||
|
|
||||||
|
app_target = list[0]
|
||||||
|
app_ver = list[1]
|
||||||
|
app_name = list[2]
|
||||||
|
|
||||||
|
if is_sfx:
|
||||||
|
sfx()
|
||||||
|
|
||||||
|
elif "-local" in sys.argv:
|
||||||
|
local_install(app_target, app_name)
|
||||||
|
|
||||||
|
elif "-installer" in sys.argv:
|
||||||
|
make_install(app_ver, app_name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Do you want to install onto this machine or create an installer?")
|
||||||
|
print("[1] local machine")
|
||||||
|
print("[2] create installer")
|
||||||
|
print("[3] exit")
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
opt = input("select an option: ")
|
||||||
|
|
||||||
|
if opt == "1":
|
||||||
|
local_install(app_target, app_name)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif opt == "2":
|
||||||
|
make_install(app_ver, app_name)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif opt == "3":
|
||||||
|
break
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(is_sfx=False)
|
147
linux_build.sh
147
linux_build.sh
|
@ -1,147 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
qt_dir="$1"
|
|
||||||
installer_file="$2"
|
|
||||||
|
|
||||||
src_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
bin_name="mrci"
|
|
||||||
app_version="3.0.0.0"
|
|
||||||
app_name="MRCI"
|
|
||||||
install_dir="/opt/$bin_name"
|
|
||||||
var_dir="/var/opt/$bin_name"
|
|
||||||
bin_dir="/usr/bin"
|
|
||||||
tmp_dir="$HOME/.cache/mrci_build"
|
|
||||||
|
|
||||||
if [ ! -d "$qt_dir" ]; then
|
|
||||||
|
|
||||||
echo "a valid path to Qt was not provided, falling back to the default: /usr/lib/x86_64-linux-gnu/qt5/bin"
|
|
||||||
|
|
||||||
qt_dir="/usr/lib/x86_64-linux-gnu/qt5/bin"
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
PATH=$qt_dir:$PATH
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$installer_file" = "" ]; then
|
|
||||||
|
|
||||||
installer_file="$src_dir/$bin_name-$app_version.run"
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$tmp_dir" ]; then
|
|
||||||
|
|
||||||
rm -rf $tmp_dir
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -eq 0 -a -d "$qt_dir" ]; then
|
|
||||||
|
|
||||||
mkdir -vp $tmp_dir
|
|
||||||
cp -r $src_dir/. $tmp_dir
|
|
||||||
cd $tmp_dir
|
|
||||||
qmake -config release
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
|
|
||||||
make
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
|
|
||||||
mkdir -v ./build/
|
|
||||||
mkdir -v ./build/sqldrivers
|
|
||||||
mkdir -v ./build/lib
|
|
||||||
ldd ./$bin_name | grep "libQt" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./build/lib
|
|
||||||
ldd ./$bin_name | grep "libicu" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./build/lib
|
|
||||||
ldd ./$bin_name | grep "libssl" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./build/lib
|
|
||||||
ldd ./$bin_name | grep "libcrypto" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./build/lib
|
|
||||||
mv -v ./$bin_name ./build/$bin_name
|
|
||||||
cp -v $qt_dir/../plugins/sqldrivers/libqsqlite.so ./build/sqldrivers
|
|
||||||
|
|
||||||
startup_script="./build/$bin_name.sh"
|
|
||||||
setup_script="./build/setup.sh"
|
|
||||||
uninstall_script="./build/uninstall.sh"
|
|
||||||
service_file="./build/$bin_name.service"
|
|
||||||
|
|
||||||
echo "#!/bin/sh" > $startup_script
|
|
||||||
echo "export QTDIR=$install_dir" >> $startup_script
|
|
||||||
echo "export QT_PLUGIN_PATH=$install_dir" >> $startup_script
|
|
||||||
echo "export LD_LIBRARY_PATH=\"$install_dir/lib:\$LD_LIBRARY_PATH\"" >> $startup_script
|
|
||||||
echo "export MRCI_DB_PATH=$var_dir/data.db" >> $startup_script
|
|
||||||
echo "$install_dir/$bin_name \$1 \$2 \$3" >> $startup_script
|
|
||||||
|
|
||||||
echo "#!/bin/sh" > $setup_script
|
|
||||||
echo "if [ -f \"$install_dir/uninstall.sh\" ]; then" >> $setup_script
|
|
||||||
echo " sh $install_dir/uninstall.sh" >> $setup_script
|
|
||||||
echo "fi" >> $setup_script
|
|
||||||
echo "if [ ! -d \"$install_dir\" ]; then" >> $setup_script
|
|
||||||
echo " sudo mkdir -p $install_dir" >> $setup_script
|
|
||||||
echo "fi" >> $setup_script
|
|
||||||
echo "if [ ! -d \"$var_dir\" ]; then" >> $setup_script
|
|
||||||
echo " sudo mkdir -p $var_dir" >> $setup_script
|
|
||||||
echo "fi" >> $setup_script
|
|
||||||
echo "cp -rfv ./lib $install_dir" >> $setup_script
|
|
||||||
echo "cp -rfv ./sqldrivers $install_dir" >> $setup_script
|
|
||||||
echo "cp -fv ./$bin_name $install_dir" >> $setup_script
|
|
||||||
echo "cp -fv ./$bin_name.sh $install_dir" >> $setup_script
|
|
||||||
echo "cp -fv ./uninstall.sh $install_dir" >> $setup_script
|
|
||||||
echo "cp -fv ./$bin_name.service /etc/systemd/system/$bin_name.service" >> $setup_script
|
|
||||||
echo "useradd -r $bin_name" >> $setup_script
|
|
||||||
echo "chmod 755 $install_dir/$bin_name" >> $setup_script
|
|
||||||
echo "chmod 755 $install_dir/$bin_name.sh" >> $setup_script
|
|
||||||
echo "chmod 755 $install_dir/uninstall.sh" >> $setup_script
|
|
||||||
echo "chmod 755 $install_dir" >> $setup_script
|
|
||||||
echo "chmod -R 755 $install_dir/lib" >> $setup_script
|
|
||||||
echo "chmod -R 755 $install_dir/sqldrivers" >> $setup_script
|
|
||||||
echo "chmod 755 /etc/systemd/system/$bin_name.service" >> $setup_script
|
|
||||||
echo "chown -R $bin_name:$bin_name $var_dir" >> $setup_script
|
|
||||||
echo "chmod -R 755 $var_dir" >> $setup_script
|
|
||||||
echo "ln -sf $install_dir/$bin_name.sh $bin_dir/$bin_name" >> $setup_script
|
|
||||||
echo "systemctl start $bin_name" >> $setup_script
|
|
||||||
echo "systemctl enable $bin_name" >> $setup_script
|
|
||||||
echo "if [ \$? -eq 0 ]; then" >> $setup_script
|
|
||||||
echo " echo \"\nInstallation finished. If you ever need to uninstall this application, run this command:\n\"" >> $setup_script
|
|
||||||
echo " echo \" $install_dir/uninstall.sh\n\"" >> $setup_script
|
|
||||||
echo "fi" >> $setup_script
|
|
||||||
|
|
||||||
echo "[Unit]" > $service_file
|
|
||||||
echo "Description=$app_name Host Daemon" >> $service_file
|
|
||||||
echo "After=network.target" >> $service_file
|
|
||||||
echo "" >> $service_file
|
|
||||||
echo "[Service]" >> $service_file
|
|
||||||
echo "Type=simple" >> $service_file
|
|
||||||
echo "User=$bin_name" >> $service_file
|
|
||||||
echo "Restart=on-failure" >> $service_file
|
|
||||||
echo "RestartSec=5" >> $service_file
|
|
||||||
echo "TimeoutStopSec=infinity" >> $service_file
|
|
||||||
echo "ExecStart=/usr/bin/env $bin_name -host" >> $service_file
|
|
||||||
echo "ExecStop=/usr/bin/env $bin_name -stop" >> $service_file
|
|
||||||
echo "" >> $service_file
|
|
||||||
echo "[Install]" >> $service_file
|
|
||||||
echo "WantedBy=multi-user.target" >> $service_file
|
|
||||||
|
|
||||||
echo "#!/bin/sh" > $uninstall_script
|
|
||||||
echo "systemctl -q stop $bin_name" >> $uninstall_script
|
|
||||||
echo "systemctl -q disable $bin_name" >> $uninstall_script
|
|
||||||
echo "rm -v /etc/systemd/system/$bin_name.service" >> $uninstall_script
|
|
||||||
echo "rm -v $bin_dir/$bin_name" >> $uninstall_script
|
|
||||||
echo "rm -rv $install_dir" >> $uninstall_script
|
|
||||||
echo "chown -R root:root $var_dir" >> $uninstall_script
|
|
||||||
echo "deluser $bin_name" >> $uninstall_script
|
|
||||||
|
|
||||||
chmod +x $setup_script
|
|
||||||
|
|
||||||
makeself ./build $installer_file "$app_name Installation" ./setup.sh
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$tmp_dir" ]; then
|
|
||||||
|
|
||||||
rm -rf $tmp_dir
|
|
||||||
|
|
||||||
fi
|
|
|
@ -126,7 +126,8 @@ void ServSettings::printSettings()
|
||||||
txtOut << "Maximum Sub-Channels: " << db.getData(COLUMN_MAX_SUB_CH).toUInt() << endl;
|
txtOut << "Maximum Sub-Channels: " << db.getData(COLUMN_MAX_SUB_CH).toUInt() << endl;
|
||||||
txtOut << "Initial Host Rank: " << db.getData(COLUMN_INITRANK).toUInt() << endl;
|
txtOut << "Initial Host Rank: " << db.getData(COLUMN_INITRANK).toUInt() << endl;
|
||||||
txtOut << "Root User: " << getUserName(rootUserId()) << endl;
|
txtOut << "Root User: " << getUserName(rootUserId()) << endl;
|
||||||
txtOut << "Database Path: " << sqlDataPath() << endl;
|
txtOut << "Working Path: " << QDir::currentPath() << endl;
|
||||||
|
txtOut << "Database: " << sqlDataPath() << endl;
|
||||||
txtOut << "Mailer Executable: " << db.getData(COLUMN_MAILERBIN).toString() << endl;
|
txtOut << "Mailer Executable: " << db.getData(COLUMN_MAILERBIN).toString() << endl;
|
||||||
txtOut << "Mailer Command: " << db.getData(COLUMN_MAIL_SEND).toString() << endl << endl;
|
txtOut << "Mailer Command: " << db.getData(COLUMN_MAIL_SEND).toString() << endl << endl;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,47 @@
|
||||||
// along with MRCI under the LICENSE.md file. If not, see
|
// along with MRCI under the LICENSE.md file. If not, see
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
QString sslCertChain()
|
||||||
|
{
|
||||||
|
return expandEnvVariables(qEnvironmentVariable(ENV_PUB_KEY, DEFAULT_PUB_KEY_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sslPrivKey()
|
||||||
|
{
|
||||||
|
return expandEnvVariables(qEnvironmentVariable(ENV_PRIV_KEY, DEFAULT_PRIV_KEY_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray rdFileContents(const QString &path, QTextStream &msg)
|
||||||
|
{
|
||||||
|
QByteArray ret;
|
||||||
|
|
||||||
|
msg << "Reading file contents: '" << path << "' ";
|
||||||
|
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
if (file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
ret = file.readAll();
|
||||||
|
|
||||||
|
if (!ret.isEmpty())
|
||||||
|
{
|
||||||
|
msg << "[pass]" << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "[fail] (0 bytes of data was read from the file, is it empty?)" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "[fail] (" << file.errorString() << ")" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
QString boolStr(bool state)
|
QString boolStr(bool state)
|
||||||
{
|
{
|
||||||
QString ret;
|
QString ret;
|
||||||
|
|
|
@ -234,6 +234,7 @@ class Session;
|
||||||
QByteArray toTEXT(const QString &txt);
|
QByteArray toTEXT(const QString &txt);
|
||||||
QByteArray fixedToTEXT(const QString &txt, int len);
|
QByteArray fixedToTEXT(const QString &txt, int len);
|
||||||
QByteArray nullTermTEXT(const QString &txt);
|
QByteArray nullTermTEXT(const QString &txt);
|
||||||
|
QByteArray rdFileContents(const QString &path, QTextStream &msg);
|
||||||
quint32 toCmdId32(quint16 cmdId, quint16 branchId);
|
quint32 toCmdId32(quint16 cmdId, quint16 branchId);
|
||||||
quint16 toCmdId16(quint32 id);
|
quint16 toCmdId16(quint32 id);
|
||||||
void serializeThread(QThread *thr);
|
void serializeThread(QThread *thr);
|
||||||
|
@ -286,6 +287,8 @@ QString getParam(const QString &key, const QStringList &args);
|
||||||
QString escapeChars(const QString &str, const QChar &escapeChr, const QChar &chr);
|
QString escapeChars(const QString &str, const QChar &escapeChr, const QChar &chr);
|
||||||
QString genSerialNumber();
|
QString genSerialNumber();
|
||||||
QString defaultPw();
|
QString defaultPw();
|
||||||
|
QString sslCertChain();
|
||||||
|
QString sslPrivKey();
|
||||||
QStringList parseArgs(const QByteArray &data, int maxArgs, int *pos = nullptr);
|
QStringList parseArgs(const QByteArray &data, int maxArgs, int *pos = nullptr);
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
|
|
15
src/db.cpp
15
src/db.cpp
|
@ -78,16 +78,7 @@ QByteArray genUniqueHash()
|
||||||
|
|
||||||
QString sqlDataPath()
|
QString sqlDataPath()
|
||||||
{
|
{
|
||||||
QString ret = qEnvironmentVariable(ENV_DB_PATH, DEFAULT_DB_PATH);
|
return expandEnvVariables(qEnvironmentVariable(ENV_DB_PATH, DEFAULT_DB_FILE));
|
||||||
|
|
||||||
ret = expandEnvVariables(ret);
|
|
||||||
|
|
||||||
QFileInfo info(ret);
|
|
||||||
QDir dir(info.path());
|
|
||||||
|
|
||||||
if (!dir.exists()) dir.mkpath(info.path());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> genSequence(int min, int max, int len)
|
QList<int> genSequence(int min, int max, int len)
|
||||||
|
@ -395,9 +386,9 @@ QString Query::errDetail()
|
||||||
|
|
||||||
txtOut << " driver error: " << errTxt << endl;
|
txtOut << " driver error: " << errTxt << endl;
|
||||||
txtOut << " query: " << qStr << jStr << wStr << limit << endl;
|
txtOut << " query: " << qStr << jStr << wStr << limit << endl;
|
||||||
txtOut << " db path: " << sqlDataPath() << endl;
|
txtOut << " database: " << sqlDataPath() << endl;
|
||||||
|
|
||||||
QFileInfo info = QFileInfo(QFileInfo(sqlDataPath()).path());
|
auto info = QFileInfo(QFileInfo(sqlDataPath()).path());
|
||||||
|
|
||||||
if (!info.isReadable())
|
if (!info.isReadable())
|
||||||
{
|
{
|
||||||
|
|
7
src/db.h
7
src/db.h
|
@ -37,21 +37,19 @@
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
|
||||||
#define APP_NAME "MRCI"
|
#define APP_NAME "MRCI"
|
||||||
#define APP_VER "3.2.1.0"
|
#define APP_VER "3.3.1.0"
|
||||||
#define APP_TARGET "mrci"
|
#define APP_TARGET "mrci"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
#define DEFAULT_MAILBIN "%COMSPEC%"
|
#define DEFAULT_MAILBIN "%COMSPEC%"
|
||||||
#define DEFAULT_MAIL_SEND "echo %message_body% | mutt -s %subject% %target_email%"
|
#define DEFAULT_MAIL_SEND "echo %message_body% | mutt -s %subject% %target_email%"
|
||||||
#define DEFAULT_DB_PATH "%PROGRAMDATA%\\mrci\\data.db"
|
|
||||||
#define DEFAULT_WORK_DIR "%PROGRAMDATA%\\mrci"
|
#define DEFAULT_WORK_DIR "%PROGRAMDATA%\\mrci"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DEFAULT_MAILBIN "/bin/sh"
|
#define DEFAULT_MAILBIN "/bin/sh"
|
||||||
#define DEFAULT_MAIL_SEND "-c \"echo %message_body% | mutt -s %subject% %target_email%\""
|
#define DEFAULT_MAIL_SEND "-c \"echo %message_body% | mutt -s %subject% %target_email%\""
|
||||||
#define DEFAULT_DB_PATH "/var/opt/mrci/data.db"
|
|
||||||
#define DEFAULT_WORK_DIR "/var/opt/mrci"
|
#define DEFAULT_WORK_DIR "/var/opt/mrci"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,6 +65,9 @@
|
||||||
#define TEMP_PW_SUB "%temp_pw%"
|
#define TEMP_PW_SUB "%temp_pw%"
|
||||||
#define USERNAME_SUB "%user_name%"
|
#define USERNAME_SUB "%user_name%"
|
||||||
#define DATE_SUB "%date%"
|
#define DATE_SUB "%date%"
|
||||||
|
#define DEFAULT_PUB_KEY_NAME "cert.pem"
|
||||||
|
#define DEFAULT_PRIV_KEY_NAME "priv.pem"
|
||||||
|
#define DEFAULT_DB_FILE "data.db"
|
||||||
#define DEFAULT_ROOT_USER "root"
|
#define DEFAULT_ROOT_USER "root"
|
||||||
#define DEFAULT_CONFIRM_SUBJECT "Email Verification"
|
#define DEFAULT_CONFIRM_SUBJECT "Email Verification"
|
||||||
#define DEFAULT_TEMP_PW_SUBJECT "Password Reset"
|
#define DEFAULT_TEMP_PW_SUBJECT "Password Reset"
|
||||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -59,8 +59,7 @@ void showHelp()
|
||||||
txtOut << " -exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only." << endl;
|
txtOut << " -exempt_cmds : run the internal module to list it's rank exempt commands. for internal use only." << endl;
|
||||||
txtOut << " -user_cmds : run the internal module to list it's user commands. for internal use only." << endl;
|
txtOut << " -user_cmds : run the internal module to list it's user commands. for internal use only." << endl;
|
||||||
txtOut << " -run_cmd : run an internal module command. for internal use only." << endl;
|
txtOut << " -run_cmd : run an internal module command. for internal use only." << endl;
|
||||||
txtOut << " -add_cert : add/update an SSL certificate for a given common name." << endl;
|
txtOut << " -load_ssl : re-load the host SSL certificate without stopping the host instance." << endl << endl;
|
||||||
txtOut << " -rm_cert : remove an SSL certificate for a given common name." << endl << endl;
|
|
||||||
txtOut << "Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:" << endl << endl;
|
txtOut << "Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:" << endl << endl;
|
||||||
txtOut << " -pipe : the named pipe used to establish a data connection with the session." << endl;
|
txtOut << " -pipe : the named pipe used to establish a data connection with the session." << endl;
|
||||||
txtOut << " -mem_ses : the shared memory key for the session." << endl;
|
txtOut << " -mem_ses : the shared memory key for the session." << endl;
|
||||||
|
@ -110,6 +109,10 @@ int main(int argc, char *argv[])
|
||||||
auto args = QCoreApplication::arguments();
|
auto args = QCoreApplication::arguments();
|
||||||
auto ret = 0;
|
auto ret = 0;
|
||||||
|
|
||||||
|
QDir dir(workDir);
|
||||||
|
|
||||||
|
if (!dir.exists()) dir.mkpath(workDir);
|
||||||
|
|
||||||
QDir::setCurrent(workDir);
|
QDir::setCurrent(workDir);
|
||||||
QCoreApplication::setApplicationName(APP_NAME);
|
QCoreApplication::setApplicationName(APP_NAME);
|
||||||
QCoreApplication::setApplicationVersion(APP_VER);
|
QCoreApplication::setApplicationVersion(APP_VER);
|
||||||
|
@ -118,7 +121,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
qInstallMessageHandler(msgHandler);
|
qInstallMessageHandler(msgHandler);
|
||||||
|
|
||||||
//args.append("-add_cert -name test"); // debug
|
//args.append("-host"); // debug
|
||||||
|
|
||||||
if (args.contains("-help", Qt::CaseInsensitive) || args.size() == 1)
|
if (args.contains("-help", Qt::CaseInsensitive) || args.size() == 1)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +134,9 @@ int main(int argc, char *argv[])
|
||||||
QTextStream(stdout) << "The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE" << endl;
|
QTextStream(stdout) << "The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE" << endl;
|
||||||
QTextStream(stdout) << "WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE." << endl << endl;
|
QTextStream(stdout) << "WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE." << endl << endl;
|
||||||
}
|
}
|
||||||
else if (args.contains("-stop", Qt::CaseInsensitive) || args.contains("-status", Qt::CaseInsensitive))
|
else if (args.contains("-stop", Qt::CaseInsensitive) ||
|
||||||
|
args.contains("-status", Qt::CaseInsensitive) ||
|
||||||
|
args.contains("-load_ssl", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
ret = shellToHost(args, app);
|
ret = shellToHost(args, app);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ void Cert::cleanup()
|
||||||
BN_free(bne);
|
BN_free(bne);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool genRSAKey(Cert *cert)
|
bool genRSAKey(Cert *cert, QTextStream &msg)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
@ -45,14 +45,30 @@ bool genRSAKey(Cert *cert)
|
||||||
{
|
{
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "Failed to assign the generated RSA key to a PKEY object." << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "Failed to generate the RSA private key." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "Failed to initialize a BIGNUM object needed to generate the RSA key." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "The x509 object did not initialize correctly." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool genX509(Cert *cert, const QString &outsideAddr)
|
bool genX509(Cert *cert, const QString &outsideAddr, QTextStream &msg)
|
||||||
{
|
{
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
auto interfaces = QNetworkInterface::allAddresses();
|
auto interfaces = QNetworkInterface::allAddresses();
|
||||||
|
@ -61,6 +77,8 @@ bool genX509(Cert *cert, const QString &outsideAddr)
|
||||||
|
|
||||||
if (!outsideAddr.isEmpty())
|
if (!outsideAddr.isEmpty())
|
||||||
{
|
{
|
||||||
|
msg << "x509 gen_wan_ip: " << outsideAddr << endl;
|
||||||
|
|
||||||
cnNames.append(outsideAddr.toUtf8());
|
cnNames.append(outsideAddr.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +86,8 @@ bool genX509(Cert *cert, const QString &outsideAddr)
|
||||||
{
|
{
|
||||||
if (addr.isGlobal())
|
if (addr.isGlobal())
|
||||||
{
|
{
|
||||||
|
msg << "x509 gen_lan_ip: " << addr.toString() << endl;
|
||||||
|
|
||||||
cnNames.append(addr.toString().toUtf8());
|
cnNames.append(addr.toString().toUtf8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +131,14 @@ bool genX509(Cert *cert, const QString &outsideAddr)
|
||||||
{
|
{
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "Failed to self-sign the generated x509 cert." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "No usable IP addresses could be found to be used as common names in the self-signed cert." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -127,14 +155,38 @@ void addExt(X509 *cert, int nid, char *value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writePrivateKey(const char *path, Cert* cert)
|
FILE *openFileForWrite(const char *path, QTextStream &msg)
|
||||||
|
{
|
||||||
|
auto file = fopen(path, "wb");
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
msg << "Cannot open file: '" << path << "' for writing. " << strerror(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void encodeErr(const char *path, QTextStream &msg)
|
||||||
|
{
|
||||||
|
msg << "Failed to encode file '" << path << "' to PEM format." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writePrivateKey(const char *path, Cert* cert, QTextStream &msg)
|
||||||
{
|
{
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
auto *file = fopen(path, "wb");
|
FILE *file = openFileForWrite(path, msg);
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
ret = PEM_write_PrivateKey(file, cert->pKey, NULL, NULL, 0, NULL, NULL);
|
if (PEM_write_PrivateKey(file, cert->pKey, NULL, NULL, 0, NULL, NULL))
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encodeErr(path, msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
@ -142,14 +194,21 @@ bool writePrivateKey(const char *path, Cert* cert)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeX509(const char *path, Cert *cert)
|
bool writeX509(const char *path, Cert *cert, QTextStream &msg)
|
||||||
{
|
{
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
auto *file = fopen(path, "wb");
|
FILE *file = openFileForWrite(path, msg);
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
ret = PEM_write_X509(file, cert->x509);
|
if (PEM_write_X509(file, cert->x509))
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encodeErr(path, msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
@ -157,15 +216,17 @@ bool writeX509(const char *path, Cert *cert)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void genDefaultSSLFiles(const QString &outsideAddr)
|
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg)
|
||||||
{
|
{
|
||||||
auto *cert = new Cert();
|
auto *cert = new Cert();
|
||||||
|
auto ret = genRSAKey(cert, msg);
|
||||||
|
|
||||||
genRSAKey(cert);
|
if (ret) ret = genX509(cert, outsideAddr, msg);
|
||||||
genX509(cert, outsideAddr);
|
if (ret) ret = writePrivateKey(DEFAULT_PRIV_KEY_NAME, cert, msg);
|
||||||
writePrivateKey(DEFAULT_PRIV_KEY_NAME, cert);
|
if (ret) ret = writeX509(DEFAULT_PUB_KEY_NAME, cert, msg);
|
||||||
writeX509(DEFAULT_PUB_KEY_NAME, cert);
|
|
||||||
|
|
||||||
cert->cleanup();
|
cert->cleanup();
|
||||||
cert->deleteLater();
|
cert->deleteLater();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,6 @@
|
||||||
|
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
|
||||||
#define DEFAULT_PUB_KEY_NAME "cert.pem"
|
|
||||||
#define DEFAULT_PRIV_KEY_NAME "priv.pem"
|
|
||||||
|
|
||||||
class Cert : public QObject
|
class Cert : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -53,11 +50,13 @@ public:
|
||||||
explicit Cert(QObject *parent = nullptr);
|
explicit Cert(QObject *parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool genRSAKey(Cert *cert);
|
FILE *openFileForWrite(const char *path, QTextStream &msg);
|
||||||
bool genX509(Cert *cert, const QString &outsideAddr);
|
bool genRSAKey(Cert *cert, QTextStream &msg);
|
||||||
bool writePrivateKey(const char *path, Cert *cert);
|
bool genX509(Cert *cert, const QString &outsideAddr, QTextStream &msg);
|
||||||
bool writeX509(const char *path, Cert *cert);
|
bool writePrivateKey(const char *path, Cert *cert, QTextStream &msg);
|
||||||
void genDefaultSSLFiles(const QString &outsideAddr);
|
bool writeX509(const char *path, Cert *cert, QTextStream &msg);
|
||||||
|
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg);
|
||||||
void addExt(X509 *cert, int nid, char *value);
|
void addExt(X509 *cert, int nid, char *value);
|
||||||
|
void encodeErr(const char *path, QTextStream &msg);
|
||||||
|
|
||||||
#endif // MAKE_CERT_H
|
#endif // MAKE_CERT_H
|
||||||
|
|
|
@ -25,11 +25,13 @@ QByteArray wrFrame(quint32 cmdId, const QByteArray &data, uchar dType)
|
||||||
return typeBa + cmdBa + sizeBa + data;
|
return typeBa + cmdBa + sizeBa + data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::Session(const QString &hostKey, QSslSocket *tcp, QObject *parent) : MemShare(parent)
|
Session::Session(const QString &hostKey, QSslSocket *tcp, QSslKey *privKey, QList<QSslCertificate> *chain, QObject *parent) : MemShare(parent)
|
||||||
{
|
{
|
||||||
currentDir = QDir::currentPath();
|
currentDir = QDir::currentPath();
|
||||||
hostMemKey = hostKey;
|
hostMemKey = hostKey;
|
||||||
tcpSocket = tcp;
|
tcpSocket = tcp;
|
||||||
|
sslKey = privKey;
|
||||||
|
sslChain = chain;
|
||||||
hookCmdId32 = 0;
|
hookCmdId32 = 0;
|
||||||
tcpFrameCmdId = 0;
|
tcpFrameCmdId = 0;
|
||||||
tcpPayloadSize = 0;
|
tcpPayloadSize = 0;
|
||||||
|
@ -374,11 +376,8 @@ void Session::dataFromClient()
|
||||||
// likely have to do the same. a ASYNC_RDY async will not
|
// likely have to do the same. a ASYNC_RDY async will not
|
||||||
// get sent until the handshake is successful.
|
// get sent until the handshake is successful.
|
||||||
|
|
||||||
auto pubKey = expandEnvVariables(qEnvironmentVariable(ENV_PUB_KEY, DEFAULT_PUB_KEY_NAME));
|
tcpSocket->setLocalCertificateChain(*sslChain);
|
||||||
auto privKey = expandEnvVariables(qEnvironmentVariable(ENV_PRIV_KEY, DEFAULT_PRIV_KEY_NAME));
|
tcpSocket->setPrivateKey(*sslKey);
|
||||||
|
|
||||||
tcpSocket->setLocalCertificate(pubKey);
|
|
||||||
tcpSocket->setPrivateKey(privKey);
|
|
||||||
tcpSocket->write(servHeader);
|
tcpSocket->write(servHeader);
|
||||||
tcpSocket->startServerEncryption();
|
tcpSocket->startServerEncryption();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ class Session : public MemShare
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QSslSocket *tcpSocket;
|
QSslSocket *tcpSocket;
|
||||||
|
QList<QSslCertificate> *sslChain;
|
||||||
|
QSslKey *sslKey;
|
||||||
QString currentDir;
|
QString currentDir;
|
||||||
QHash<QString, QStringList> modCmdNames;
|
QHash<QString, QStringList> modCmdNames;
|
||||||
QHash<quint32, QList<QByteArray> > frameQueue;
|
QHash<quint32, QList<QByteArray> > frameQueue;
|
||||||
|
@ -100,7 +102,7 @@ private slots:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Session(const QString &hostKey, QSslSocket *tcp, QObject *parent = nullptr);
|
explicit Session(const QString &hostKey, QSslSocket *tcp, QSslKey *privKey, QList<QSslCertificate> *chain, QObject *parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,9 @@ bool TCPServer::createPipe()
|
||||||
|
|
||||||
void TCPServer::replyFromIpify(QNetworkReply *reply)
|
void TCPServer::replyFromIpify(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
genDefaultSSLFiles(reply->readAll());
|
wanIP = reply->readAll();
|
||||||
|
|
||||||
|
loadSSLData(false);
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
@ -101,8 +103,6 @@ bool TCPServer::start()
|
||||||
db.addColumn(COLUMN_MAXSESSIONS);
|
db.addColumn(COLUMN_MAXSESSIONS);
|
||||||
db.exec();
|
db.exec();
|
||||||
|
|
||||||
qNam->get(QNetworkRequest(QUrl("https://api.ipify.org")));
|
|
||||||
|
|
||||||
maxSessions = db.getData(COLUMN_MAXSESSIONS).toUInt();
|
maxSessions = db.getData(COLUMN_MAXSESSIONS).toUInt();
|
||||||
|
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
|
@ -126,6 +126,8 @@ bool TCPServer::start()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
qNam->get(QNetworkRequest(QUrl("https://api.ipify.org")));
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
flags |= ACCEPTING;
|
flags |= ACCEPTING;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +219,10 @@ void TCPServer::procPipeIn()
|
||||||
|
|
||||||
controlSocket->write(toTEXT("\n"));
|
controlSocket->write(toTEXT("\n"));
|
||||||
}
|
}
|
||||||
|
else if (args.contains("-load_ssl", Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
controlSocket->write(toTEXT(loadSSLData(true)));
|
||||||
|
}
|
||||||
else if (args.contains("-status", Qt::CaseInsensitive))
|
else if (args.contains("-status", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
|
@ -237,7 +243,10 @@ void TCPServer::procPipeIn()
|
||||||
txtOut << "Active Port: " << serverPort() << endl;
|
txtOut << "Active Port: " << serverPort() << endl;
|
||||||
txtOut << "Set Address: " << db.getData(COLUMN_IPADDR).toString() << endl;
|
txtOut << "Set Address: " << db.getData(COLUMN_IPADDR).toString() << endl;
|
||||||
txtOut << "Set Port: " << db.getData(COLUMN_PORT).toUInt() << endl;
|
txtOut << "Set Port: " << db.getData(COLUMN_PORT).toUInt() << endl;
|
||||||
txtOut << "Database Path: " << sqlDataPath() << endl << endl;
|
txtOut << "Working Path: " << QDir::currentPath() << endl;
|
||||||
|
txtOut << "Database: " << sqlDataPath() << endl;
|
||||||
|
txtOut << "SSL Chain: " << sslCertChain() << endl;
|
||||||
|
txtOut << "SSL Private: " << sslPrivKey() << endl << endl;
|
||||||
|
|
||||||
hostSharedMem->unlock();
|
hostSharedMem->unlock();
|
||||||
controlSocket->write(toTEXT(text));
|
controlSocket->write(toTEXT(text));
|
||||||
|
@ -277,7 +286,7 @@ void TCPServer::incomingConnection(qintptr socketDescriptor)
|
||||||
soc->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, buffSize);
|
soc->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, buffSize);
|
||||||
soc->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption, buffSize);
|
soc->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption, buffSize);
|
||||||
|
|
||||||
auto *ses = new Session(hostKey, soc, nullptr);
|
auto *ses = new Session(hostKey, soc, &sslKey, &sslChain, nullptr);
|
||||||
auto *thr = new QThread(nullptr);
|
auto *thr = new QThread(nullptr);
|
||||||
|
|
||||||
connect(thr, &QThread::finished, soc, &QSslSocket::deleteLater);
|
connect(thr, &QThread::finished, soc, &QSslSocket::deleteLater);
|
||||||
|
@ -308,3 +317,137 @@ void TCPServer::incomingConnection(qintptr socketDescriptor)
|
||||||
hostSharedMem->unlock();
|
hostSharedMem->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TCPServer::applyPrivKey(const QString &path, QTextStream &msg)
|
||||||
|
{
|
||||||
|
auto bytes = rdFileContents(path, msg);
|
||||||
|
|
||||||
|
if (!bytes.isEmpty())
|
||||||
|
{
|
||||||
|
msg << "Attempting to load the private key with RSA. ";
|
||||||
|
|
||||||
|
QSslKey key(bytes, QSsl::Rsa);
|
||||||
|
|
||||||
|
if (key.isNull())
|
||||||
|
{
|
||||||
|
msg << "[fail]" << endl;
|
||||||
|
msg << "Attempting to load the private key with DSA. ";
|
||||||
|
|
||||||
|
key = QSslKey(bytes, QSsl::Dsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isNull())
|
||||||
|
{
|
||||||
|
msg << "[fail]" << endl;
|
||||||
|
msg << "Attempting to load the private key with Elliptic Curve. ";
|
||||||
|
|
||||||
|
key = QSslKey(bytes, QSsl::Ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isNull())
|
||||||
|
{
|
||||||
|
msg << "[fail]" << endl;
|
||||||
|
msg << "Attempting to load the private key with Diffie-Hellman. ";
|
||||||
|
|
||||||
|
key = QSslKey(bytes, QSsl::Dh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isNull())
|
||||||
|
{
|
||||||
|
msg << "[fail]" << endl;
|
||||||
|
msg << "Attempting to load the private key as a black box. ";
|
||||||
|
|
||||||
|
key = QSslKey(bytes, QSsl::Opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isNull())
|
||||||
|
{
|
||||||
|
msg << "[fail]" << endl << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "[pass]" << endl << endl;
|
||||||
|
|
||||||
|
sslKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPServer::applyCerts(const QStringList &list, QTextStream &msg)
|
||||||
|
{
|
||||||
|
sslChain.clear();
|
||||||
|
|
||||||
|
for (auto file : list)
|
||||||
|
{
|
||||||
|
sslChain.append(QSslCertificate(rdFileContents(file, msg)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TCPServer::loadSSLData(bool onReload)
|
||||||
|
{
|
||||||
|
QString txtMsg;
|
||||||
|
QTextStream stream(&txtMsg);
|
||||||
|
|
||||||
|
auto chain = sslCertChain().split(":");
|
||||||
|
auto priv = sslPrivKey();
|
||||||
|
auto allCertsExists = true;
|
||||||
|
auto privKeyExists = QFile::exists(priv);
|
||||||
|
|
||||||
|
stream << "Private key: " << priv << endl;
|
||||||
|
|
||||||
|
if (!privKeyExists)
|
||||||
|
{
|
||||||
|
stream << " ^(the private key does not exists)" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cert : chain)
|
||||||
|
{
|
||||||
|
stream << "Cert: " << cert << endl;
|
||||||
|
|
||||||
|
if (!QFile::exists(cert))
|
||||||
|
{
|
||||||
|
stream << " ^(this cert does not exists)" << endl;
|
||||||
|
|
||||||
|
allCertsExists = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain.isEmpty())
|
||||||
|
{
|
||||||
|
stream << "No cert files are defined in the env." << endl;
|
||||||
|
|
||||||
|
allCertsExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << endl;
|
||||||
|
|
||||||
|
if (allCertsExists && privKeyExists)
|
||||||
|
{
|
||||||
|
if (onReload && (priv == DEFAULT_PRIV_KEY_NAME) && (sslCertChain() == DEFAULT_PUB_KEY_NAME))
|
||||||
|
{
|
||||||
|
stream << "Re-generating self-signed cert." << endl;
|
||||||
|
|
||||||
|
if (genDefaultSSLFiles(wanIP, stream))
|
||||||
|
{
|
||||||
|
stream << endl << "complete." << endl << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPrivKey(priv, stream);
|
||||||
|
applyCerts(chain, stream);
|
||||||
|
}
|
||||||
|
else if ((priv == DEFAULT_PRIV_KEY_NAME) && (sslCertChain() == DEFAULT_PUB_KEY_NAME))
|
||||||
|
{
|
||||||
|
stream << "Generating self-signed cert." << endl;
|
||||||
|
|
||||||
|
if (genDefaultSSLFiles(wanIP, stream))
|
||||||
|
{
|
||||||
|
stream << endl << "The default self-signed cert files are generated successfully." << endl << endl;
|
||||||
|
|
||||||
|
applyPrivKey(priv, stream);
|
||||||
|
applyCerts(chain, stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return txtMsg;
|
||||||
|
}
|
||||||
|
|
|
@ -35,13 +35,19 @@ private:
|
||||||
QLocalServer *controlPipe;
|
QLocalServer *controlPipe;
|
||||||
QLocalSocket *controlSocket;
|
QLocalSocket *controlSocket;
|
||||||
char *hostLoad;
|
char *hostLoad;
|
||||||
|
QList<QSslCertificate> sslChain;
|
||||||
|
QSslKey sslKey;
|
||||||
QString controlPipePath;
|
QString controlPipePath;
|
||||||
QString hostKey;
|
QString hostKey;
|
||||||
|
QString wanIP;
|
||||||
quint32 maxSessions;
|
quint32 maxSessions;
|
||||||
quint32 flags;
|
quint32 flags;
|
||||||
|
|
||||||
|
QString loadSSLData(bool onReload);
|
||||||
bool servOverloaded();
|
bool servOverloaded();
|
||||||
bool createPipe();
|
bool createPipe();
|
||||||
|
void applyPrivKey(const QString &path, QTextStream &msg);
|
||||||
|
void applyCerts(const QStringList &list, QTextStream &msg);
|
||||||
void incomingConnection(qintptr socketDescriptor);
|
void incomingConnection(qintptr socketDescriptor);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user