diff --git a/.gitignore b/.gitignore index 64c4f73e..637243fe 100755 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,14 @@ core venv/* onionr/fs* +# log files +output.log +*.log +onionr/output.log +onionr/*.log +onionr/data/output.log +onionr/data/*.log + # package files onionr-*.pkg.tar.gz pkg/ diff --git a/Makefile b/Makefile index 2f48cf0f..982b1dc0 100755 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ reset: @echo "Hard-resetting Onionr..." rm -rf onionr/$(ONIONR_HOME)/ | true > /dev/null 2>&1 cd onionr/static-data/www/ui/; rm -rf ./dist; python compile.py - #@./onionr.sh.sh version | grep -v "Failed" --color=always + #@./onionr.sh version | grep -v "Failed" --color=always plugins-reset: @echo "Resetting plugins..." diff --git a/docs/onionr-icon.png b/docs/onionr-icon.png new file mode 100755 index 00000000..861af295 Binary files /dev/null and b/docs/onionr-icon.png differ diff --git a/install/install_arch.sh b/install/install_arch.sh new file mode 100755 index 00000000..acd3fb1e --- /dev/null +++ b/install/install_arch.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +EXECUTABLE='/usr/bin/onionr' +OUTPUT_DIR='/usr/share/onionr' +DATA_DIR='/etc/onionr' +LOG_DIR='/var/log/onionr' + +BRANCH='master' + +# setup error handlers + +set -e + +trap "echo -e '\033[31mOnionr installation failed.\033[0m' >&2; exit 1337" ERR INT TERM + +# require root permissions + +if ! [ $(id -u) = 0 ]; then + echo 'This script must be run as root.' >&2 + exit 1337 +fi + +# install basic dependencies + +pacman --needed --noconfirm -S git curl python python-pip tor + +# get the repository + +rm -rf "$OUTPUT_DIR" "$DATA_DIR" "$LOG_DIR" + +git clone https://gitlab.com/beardog/onionr "$OUTPUT_DIR" + +cd "$OUTPUT_DIR" +git checkout "$BRANCH" + +# install python dependencies + +pip3 install --no-input -r "$OUTPUT_DIR/requirements.txt" --require-hashes + +# create nologin onionr user if not exists + +id -u onionr &>/dev/null || useradd -r -s /sbin/nologin onionr + +chmod 755 "$OUTPUT_DIR" +chown -R onionr:onionr "$OUTPUT_DIR" + +# create directories + +mkdir -p "$OUTPUT_DIR/onionr/data" "$LOG_DIR" +mv "$OUTPUT_DIR/onionr/data" "$DATA_DIR" + +chmod -R 750 "$DATA_DIR" "$LOG_DIR" +chown -R onionr:onionr "$DATA_DIR" "$LOG_DIR" + +# create executable + +cp "$OUTPUT_DIR/install/onionr" "$EXECUTABLE" + +chmod 755 "$EXECUTABLE" +chown root:root "$EXECUTABLE" + +# create systemd service + +SERVICE='/etc/systemd/system/onionr.service' + +cp "$OUTPUT_DIR/install/onionr.service" "$SERVICE" + +chmod 644 "$SERVICE" +chown root:root "$SERVICE" + +systemctl daemon-reload +systemctl enable onionr +systemctl start onionr + +# pretty header thing + +"$EXECUTABLE" --header 'Onionr successfully installed.' + +# and we're good! + +trap - ERR + +exit 0 diff --git a/install/install_debian.sh b/install/install_debian.sh new file mode 100755 index 00000000..4f37f56f --- /dev/null +++ b/install/install_debian.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +EXECUTABLE='/usr/bin/onionr' +OUTPUT_DIR='/usr/share/onionr' +DATA_DIR='/etc/onionr' +LOG_DIR='/var/log/onionr' + +BRANCH='master' + +# setup error handlers + +set -e + +trap "echo -e '\033[31mOnionr installation failed.\033[0m' >&2; exit 1337" ERR INT TERM + +# require root permissions + +if ! [ $(id -u) = 0 ]; then + echo 'This script must be run as root.' >&2 + exit 1337 +fi + +# install basic dependencies + +apt -y install git curl python3.7 python3-pip python3-setuptools tor + +# get the repository + +rm -rf "$OUTPUT_DIR" "$DATA_DIR" "$LOG_DIR" + +git clone https://gitlab.com/beardog/onionr "$OUTPUT_DIR" + +cd "$OUTPUT_DIR" +git checkout "$BRANCH" + +# install python dependencies + +python3.7 -m pip install --no-input -r "$OUTPUT_DIR/requirements.txt" --require-hashes + +# create nologin onionr user if not exists + +id -u onionr &>/dev/null || useradd -r -s /sbin/nologin onionr + +chmod 755 "$OUTPUT_DIR" +chown -R onionr:onionr "$OUTPUT_DIR" + +# create directories + +mkdir -p "$OUTPUT_DIR/onionr/data" "$LOG_DIR" +mv "$OUTPUT_DIR/onionr/data" "$DATA_DIR" + +chmod -R 750 "$DATA_DIR" "$LOG_DIR" +chown -R onionr:onionr "$DATA_DIR" "$LOG_DIR" + +# create executable + +cp "$OUTPUT_DIR/install/onionr" "$EXECUTABLE" + +chmod 755 "$EXECUTABLE" +chown root:root "$EXECUTABLE" + +# create systemd service + +SERVICE='/etc/systemd/system/onionr.service' + +cp "$OUTPUT_DIR/install/onionr.service" "$SERVICE" + +chmod 644 "$SERVICE" +chown root:root "$SERVICE" + +systemctl daemon-reload +systemctl enable onionr +systemctl start onionr + +# pretty header thing + +"$EXECUTABLE" --header 'Onionr successfully installed.' + +# and we're good! + +trap - ERR + +exit 0 diff --git a/install/onionr b/install/onionr new file mode 100755 index 00000000..31fd58cc --- /dev/null +++ b/install/onionr @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +[ "root" != "$USER" ] && exec sudo $0 "$@" + +export OUTPUT_DIR=${OUTPUT_DIR:=/usr/share/onionr} +export ONIONR_HOME=${ONIONR_HOME:=/etc/onionr} +export LOG_DIR=${LOG_DIR:=/var/log/onionr} + +cd "$OUTPUT_DIR" +exec su onionr -s /bin/sh -c "./onionr.sh ""$@""" diff --git a/install/onionr.service b/install/onionr.service new file mode 100644 index 00000000..0f2a42b6 --- /dev/null +++ b/install/onionr.service @@ -0,0 +1,15 @@ +[Unit] +Description=Onionr Daemon +Requires=network.target tor.service +After=network.target tor.service + +[Service] +Environment="DATA_DIR=/usr/share/onionr" +Environment="LOG_DIR=/var/log/onionr/" +ExecStart=/usr/bin/onionr --start +ExecStop=/usr/bin/onionr --stop +Type=simple +Restart=always + +[Install] +WantedBy=tor.service diff --git a/onionr/config.py b/onionr/config.py index 960286f6..fe093b57 100755 --- a/onionr/config.py +++ b/onionr/config.py @@ -20,13 +20,11 @@ import os, json, logger -try: - dataDir = os.environ['ONIONR_HOME'] - if not dataDir.endswith('/'): - dataDir += '/' -except KeyError: - dataDir = 'data/' - +# set data dir +dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) +if not dataDir.endswith('/'): + dataDir += '/' + _configfile = os.path.abspath(dataDir + 'config.json') _config = {} diff --git a/onionr/core.py b/onionr/core.py index f178fefd..1cbce026 100755 --- a/onionr/core.py +++ b/onionr/core.py @@ -39,12 +39,10 @@ class Core: Initialize Core Onionr library ''' - try: - self.dataDir = os.environ['ONIONR_HOME'] - if not self.dataDir.endswith('/'): - self.dataDir += '/' - except KeyError: - self.dataDir = 'data/' + # set data dir + self.dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) + if not self.dataDir.endswith('/'): + self.dataDir += '/' try: self.onionrInst = None diff --git a/onionr/logger.py b/onionr/logger.py index 18dfdf1d..34dc4d06 100755 --- a/onionr/logger.py +++ b/onionr/logger.py @@ -64,10 +64,9 @@ class colors: ''' Use the bitwise operators to merge these settings ''' +USE_ANSI = 0b100 if os.name == 'nt': USE_ANSI = 0b000 -else: - USE_ANSI = 0b100 OUTPUT_TO_CONSOLE = 0b010 OUTPUT_TO_FILE = 0b001 @@ -80,7 +79,7 @@ LEVEL_IMPORTANT = 6 _type = OUTPUT_TO_CONSOLE | USE_ANSI # the default settings for logging _level = LEVEL_DEBUG # the lowest level to log -_outputfile = './output.log' # the file to log to +_outputfile = 'data/onionr.log' # the file to log to def set_settings(type): ''' diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py index 2898256c..4f6281c9 100755 --- a/onionr/netcontroller.py +++ b/onionr/netcontroller.py @@ -46,12 +46,10 @@ class NetController: ''' def __init__(self, hsPort, apiServerIP='127.0.0.1'): - try: - self.dataDir = os.environ['ONIONR_HOME'] - if not self.dataDir.endswith('/'): - self.dataDir += '/' - except KeyError: - self.dataDir = 'data/' + # set data dir + self.dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) + if not self.dataDir.endswith('/'): + self.dataDir += '/' self.torConfigLocation = self.dataDir + 'torrc' self.readyState = False @@ -165,7 +163,7 @@ HiddenServicePort 80 ''' + self.apiServerIP + ''':''' + str(self.hsPort) except KeyboardInterrupt: logger.fatal('Got keyboard interrupt.', timestamp = False, level = logger.LEVEL_IMPORTANT) return False - + logger.debug('Finished starting Tor.', timestamp=True) self.readyState = True diff --git a/onionr/onionr.py b/onionr/onionr.py index 3dff5cc3..532c87d5 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -62,12 +62,13 @@ class Onionr: except FileNotFoundError: pass - try: - self.dataDir = os.environ['ONIONR_HOME'] - if not self.dataDir.endswith('/'): - self.dataDir += '/' - except KeyError: - self.dataDir = 'data/' + # set data dir + self.dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) + if not self.dataDir.endswith('/'): + self.dataDir += '/' + + # set log file + logger.set_file(os.environ.get('LOG_DIR', 'data') + '/onionr.log') # Load global configuration data data_exists = Onionr.setupConfig(self.dataDir, self = self) @@ -144,19 +145,27 @@ class Onionr: self.execute(command) return - + def exitSigterm(self, signum, frame): self.killed = True def setupConfig(dataDir, self = None): setupconfig.setup_config(dataDir, self) + def cmdHeader(self): + if len(sys.argv) >= 3: + self.header(logger.colors.fg.pink + sys.argv[2].replace('Onionr', logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink)) + else: + self.header(None) + def header(self, message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'): if os.path.exists('static-data/header.txt') and logger.get_level() <= logger.LEVEL_INFO: with open('static-data/header.txt', 'rb') as file: # only to stdout, not file or log or anything sys.stderr.write(file.read().decode().replace('P', logger.colors.fg.pink).replace('W', logger.colors.reset + logger.colors.bold).replace('G', logger.colors.fg.green).replace('\n', logger.colors.reset + '\n').replace('B', logger.colors.bold).replace('A', '%s' % API_VERSION).replace('V', ONIONR_VERSION)) - logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n', sensitive=True) + + if not message is None: + logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n', sensitive=True) def doExport(self, bHash): exportDir = self.dataDir + 'block-export/' @@ -220,13 +229,13 @@ class Onionr: def showDetails(self): commands.onionrstatistics.show_details(self) - + def openHome(self): commands.open_home(self) def addID(self): commands.pubkeymanager.add_ID(self) - + def changeID(self): commands.pubkeymanager.change_ID(self) @@ -385,7 +394,7 @@ class Onionr: ''' Displays a message suggesting help ''' - if __name__ == '__main__': + if __name__ == '__main__': logger.info('Do ' + logger.colors.bold + sys.argv[0] + ' --help' + logger.colors.reset + logger.colors.fg.green + ' for Onionr help.') def start(self, input = False, override = False): diff --git a/onionr/onionrcommands/__init__.py b/onionr/onionrcommands/__init__.py index 2889f182..bf10f4ed 100644 --- a/onionr/onionrcommands/__init__.py +++ b/onionr/onionrcommands/__init__.py @@ -53,6 +53,7 @@ def get_commands(onionr_inst): return {'': onionr_inst.showHelpSuggestion, 'help': onionr_inst.showHelp, 'version': onionr_inst.version, + 'header': onionr_inst.cmdHeader, 'config': onionr_inst.configure, 'start': onionr_inst.start, 'stop': onionr_inst.killDaemon, @@ -168,4 +169,4 @@ cmd_help = { 'add-id': 'Generate a new ID (key pair)', 'change-id': 'Change active ID', 'open-home': 'Open your node\'s home/info screen' - } \ No newline at end of file + } diff --git a/onionr/onionrplugins.py b/onionr/onionrplugins.py index a7560957..7595805b 100755 --- a/onionr/onionrplugins.py +++ b/onionr/onionrplugins.py @@ -21,12 +21,10 @@ import os, re, importlib, config, logger import onionrevents as events -try: - dataDir = os.environ['ONIONR_HOME'] - if not dataDir.endswith('/'): - dataDir += '/' -except KeyError: - dataDir = 'data/' +# set data dir +dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) +if not dataDir.endswith('/'): + dataDir += '/' _pluginsfolder = dataDir + 'plugins/' _instances = dict() @@ -157,6 +155,28 @@ def stop(name, onionr = None): return None +# credit: https://stackoverflow.com/a/29589414 +def import_module_from_file(full_path_to_module): + """ + Import a module given the full path/filename of the .py file + + Python 3.4 + + """ + + module = None + + # Get module name and path from full path + module_dir, module_file = os.path.split(full_path_to_module) + module_name, module_ext = os.path.splitext(module_file) + + # Get module "spec" from filename + spec = importlib.util.spec_from_file_location(module_name,full_path_to_module) + + module = spec.loader.load_module() + + return module + def get_plugin(name): ''' Returns the instance of a module @@ -167,7 +187,7 @@ def get_plugin(name): if str(name).lower() in _instances: return _instances[str(name).lower()] else: - _instances[str(name).lower()] = importlib.import_module(get_plugins_folder(name, False).replace('/', '.') + 'main') + _instances[str(name).lower()] = import_module_from_file(get_plugins_folder(name, False) + 'main.py') return get_plugin(name) def get_plugins():