From 453e8588c578218f8072caffce21af67a055417c Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Tue, 30 Jul 2019 00:19:22 -0500 Subject: [PATCH] progress removing onionr.py --- .gitignore | 1 + onionr/__init__.py | 63 +++++++++++++++++++++++ onionr/etc/onionrvalues.py | 5 ++ onionr/httpapi/__init__.py | 1 - onionr/onionr.py | 53 ++----------------- onionr/onionrcommands/daemonlaunch.py | 4 +- onionr/onionrcommands/exportblocks.py | 6 +-- onionr/onionrcommands/onionrstatistics.py | 6 +-- onionr/onionrutils/basicrequests.py | 4 +- onionr/setup/__init__.py | 3 ++ onionr/setup/defaultpluginsetup.py | 21 ++++++++ onionr/{ => setup}/setupconfig.py | 18 +++++-- onionr/static-data/header.txt | 2 +- onionr/utils/getconsolewidth.py | 15 ++++++ onionr/utils/gethostname.py | 10 ++++ onionr/utils/logoheader.py | 12 +++++ onionr/utils/readstatic.py | 4 +- 17 files changed, 164 insertions(+), 64 deletions(-) create mode 100644 onionr/setup/__init__.py create mode 100644 onionr/setup/defaultpluginsetup.py rename onionr/{ => setup}/setupconfig.py (78%) create mode 100644 onionr/utils/getconsolewidth.py create mode 100644 onionr/utils/gethostname.py create mode 100644 onionr/utils/logoheader.py diff --git a/.gitignore b/.gitignore index 7573da9c..e6af0243 100755 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ onionr/data/*.log onionr-*.pkg.tar.gz pkg/ src/ +spawnnodes.py \ No newline at end of file diff --git a/onionr/__init__.py b/onionr/__init__.py index e69de29b..c5f5bfaa 100755 --- a/onionr/__init__.py +++ b/onionr/__init__.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +''' + Onionr - Private P2P Communication + + This file initializes Onionr when ran to be a daemon or with commands + + Run with 'help' for usage. +''' +''' + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +''' +# Set the user's locale for encoding reasons +import locale +locale.setlocale(locale.LC_ALL, '') + +# Import standard libraries +import sys + +# 3rd party lib imports +# Ensure that PySocks is installed +try: + from urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + raise ImportError("You need the PySocks module (for use with socks5 proxy to use Tor)") + +# Onionr imports +from etc import onionrvalues # For different Onionr related constants such as versions +from onionr import setup + +# Ensure we have at least the minimum python version +if sys.version_info[0] == 2 or sys.version_info[1] < onionrvalues.MIN_PY_VERSION: + sys.stderr.write('Error, Onionr requires Python 3.%s+\n' % (onionrvalues.MIN_PY_VERSION,)) + sys.exit(1) + +# Ensure Python interpreter is not optimized TODO: Remove asserts and replace with ifs +from utils import detectoptimization +if detectoptimization.detect_optimization(): + sys.stderr.write('Error, Onionr cannot be run with an optimized Python interpreter\n') + sys.exit(1) + +# Create Onionr data directories, must be done before most imports +from utils import createdirs +createdirs.create_dirs() + +setup.setup_config() +setup.setup_default_plugins() + +def onionr_main(): + return + +if __name__ == "__main__": + onionr_main() \ No newline at end of file diff --git a/onionr/etc/onionrvalues.py b/onionr/etc/onionrvalues.py index 836c6133..cd647954 100755 --- a/onionr/etc/onionrvalues.py +++ b/onionr/etc/onionrvalues.py @@ -19,6 +19,11 @@ ''' DENIABLE_PEER_ADDRESS = "OVPCZLOXD6DC5JHX4EQ3PSOGAZ3T24F75HQLIUZSDSMYPEOXCPFA====" PASSWORD_LENGTH = 25 +ONIONR_TAGLINE = 'Private P2P Communication - GPLv3 - https://Onionr.net' +ONIONR_VERSION = '0.0.0' # for debugging and stuff +ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION) +API_VERSION = '0' # increments of 1; only change when something fundamental about how the API works changes. This way other nodes know how to communicate without learning too much information about you. +MIN_PY_VERSION = 6 class OnionrValues: def __init__(self): self.passwordLength = 20 diff --git a/onionr/httpapi/__init__.py b/onionr/httpapi/__init__.py index f21c261b..ca9a2b7a 100755 --- a/onionr/httpapi/__init__.py +++ b/onionr/httpapi/__init__.py @@ -18,7 +18,6 @@ along with this program. If not, see . ''' import onionrplugins -API_VERSION = 0 def load_plugin_blueprints(flaskapp, blueprint='flask_blueprint'): '''Iterate enabled plugins and load any http endpoints they have''' for plugin in onionrplugins.get_enabled_plugins(): diff --git a/onionr/onionr.py b/onionr/onionr.py index fc760d20..216c0b1d 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -21,11 +21,7 @@ along with this program. If not, see . ''' import sys -ONIONR_TAGLINE = 'Private P2P Communication - GPLv3 - https://Onionr.net' -ONIONR_VERSION = '0.0.0' # for debugging and stuff -ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION) -API_VERSION = '0' # increments of 1; only change when something fundamental about how the API works changes. This way other nodes know how to communicate without learning too much information about you. -MIN_PY_VERSION = 6 +from etc import onionrvalues if sys.version_info[0] == 2 or sys.version_info[1] < MIN_PY_VERSION: sys.stderr.write('Error, Onionr requires Python 3.%s+\n' % (MIN_PY_VERSION,)) sys.exit(1) @@ -58,7 +54,7 @@ class Onionr: Main Onionr class. This is for the CLI program, and does not handle much of the logic. In general, external programs and plugins should not use this class. ''' - self.API_VERSION = API_VERSION + self.API_VERSION = onionrvalues.API_VERSION self.userRunDir = os.getcwd() # Directory user runs the program from self.killed = False self.config = config @@ -118,7 +114,7 @@ class Onionr: randomPort = netcontroller.get_open_port() config.set('client.public.port', randomPort, savefile=True) if type(config.get('client.api_version')) is type(None): - config.set('client.api_version', API_VERSION, savefile=True) + config.set('client.api_version', onionrvalues.API_VERSION, savefile=True) self.cmds = commands.get_commands(self) self.cmdhelp = commands.cmd_help @@ -140,9 +136,6 @@ class Onionr: def exitSigterm(self, signum, frame): self.killed = True - def setupConfig(self): - return setupconfig.setup_config(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)) @@ -155,15 +148,6 @@ class Onionr: 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)) - - if not message is None: - logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n', terminal=True) - def doExport(self, bHash): exportDir = self.dataDir + 'block-export/' if not os.path.exists(exportDir): @@ -185,37 +169,10 @@ class Onionr: except FileNotFoundError: pass - def get_hostname(self): - try: - with open(self.dataDir + 'hs/hostname', 'r') as hostname: - return hostname.read().strip() - except FileNotFoundError: - return "Not Generated" - except Exception: - return None - - def getConsoleWidth(self): - ''' - Returns an integer, the width of the terminal/cmd window - ''' - - columns = 80 - - try: - columns = int(os.popen('stty size', 'r').read().split()[1]) - except: - # if it errors, it's probably windows, so default to 80. - pass - - return columns - ''' Handle command line commands ''' - def exportBlock(self): - commands.exportblocks.export_block(self) - def showDetails(self): commands.onionrstatistics.show_details(self) @@ -303,9 +260,9 @@ class Onionr: Displays the Onionr version ''' - function('Onionr v%s (%s) (API v%s)' % (ONIONR_VERSION, platform.machine(), API_VERSION), terminal=True) + function('Onionr v%s (%s) (API v%s)' % (onionrvalues.ONIONR_VERSION, platform.machine(), onionrvalues.API_VERSION), terminal=True) if verbosity >= 1: - function(ONIONR_TAGLINE, terminal=True) + function(onionrvalues.ONIONR_TAGLINE, terminal=True) if verbosity >= 2: function('Running on %s %s' % (platform.platform(), platform.release()), terminal=True) function('Onionr data dir: %s' % self.dataDir) diff --git a/onionr/onionrcommands/daemonlaunch.py b/onionr/onionrcommands/daemonlaunch.py index 3c0e6b74..f693fcb2 100755 --- a/onionr/onionrcommands/daemonlaunch.py +++ b/onionr/onionrcommands/daemonlaunch.py @@ -27,7 +27,7 @@ from onionrutils import localcommand import filepaths from coredb import daemonqueue from onionrcrypto import getourkeypair -from utils import hastor +from utils import hastor, logoheader def _proper_shutdown(o_inst): localcommand.local_command('shutdown') @@ -62,7 +62,7 @@ def daemon(o_inst): logger.raw('', terminal=True) # print nice header thing :) if o_inst.config.get('general.display_header', True): - o_inst.header() + logoheader.header() o_inst.version(verbosity = 5, function = logger.info) logger.debug('Python version %s' % platform.python_version()) diff --git a/onionr/onionrcommands/exportblocks.py b/onionr/onionrcommands/exportblocks.py index 44f9b945..77e88439 100755 --- a/onionr/onionrcommands/exportblocks.py +++ b/onionr/onionrcommands/exportblocks.py @@ -22,14 +22,14 @@ import logger, onionrstorage from utils import createdirs from onionrutils import stringvalidators import filepaths -def doExport(o_inst, bHash): +def doExport(bHash): createdirs.create_dirs() data = onionrstorage.getData(bHash) with open('%s/%s.dat' % (filepaths.export_location, bHash), 'wb') as exportFile: exportFile.write(data) logger.info('Block exported as file', terminal=True) -def export_block(o_inst): +def export_block(): exportDir = filepaths.export_location try: assert stringvalidators.validate_hash(sys.argv[2]) @@ -38,4 +38,4 @@ def export_block(o_inst): sys.exit(1) else: bHash = sys.argv[2] - doExport(o_inst, bHash) \ No newline at end of file + doExport(bHash) \ No newline at end of file diff --git a/onionr/onionrcommands/onionrstatistics.py b/onionr/onionrcommands/onionrstatistics.py index 94e666dc..b3883db5 100755 --- a/onionr/onionrcommands/onionrstatistics.py +++ b/onionr/onionrcommands/onionrstatistics.py @@ -22,7 +22,7 @@ import logger from onionrblockapi import Block import onionr from onionrutils import checkcommunicator, mnemonickeys -from utils import sizeutils +from utils import sizeutils, gethostname, getconsolewidth from coredb import blockmetadb, daemonqueue, keydb import onionrcrypto def show_stats(o_inst): @@ -60,7 +60,7 @@ def show_stats(o_inst): # pre-processing maxlength = 0 - width = o_inst.getConsoleWidth() + width = getconsolewidth.get_console_width() for key, val in messages.items(): if not (type(val) is bool and val is True): maxlength = max(len(key), maxlength) @@ -86,7 +86,7 @@ def show_stats(o_inst): def show_details(o_inst): details = { - 'Node Address' : o_inst.get_hostname(), + 'Node Address' : gethostname.get_hostname(), 'Web Password' : o_inst.getWebPassword(), 'Public Key' : onionrcrypto.pub_key, 'Human-readable Public Key' : mnemonickeys.get_human_readable_ID() diff --git a/onionr/onionrutils/basicrequests.py b/onionr/onionrutils/basicrequests.py index d3d29129..33f8343d 100644 --- a/onionr/onionrutils/basicrequests.py +++ b/onionr/onionrutils/basicrequests.py @@ -19,7 +19,7 @@ ''' import requests, streamedrequests import logger, onionrexceptions -import httpapi +from etc import onionrvalues def do_post_request(onionr_inst, url, data={}, port=0, proxyType='tor', max_size=10000): ''' Do a POST request through a local tor or i2p instance @@ -49,7 +49,7 @@ def do_get_request(url, port=0, proxyType='tor', ignoreAPI=False, returnHeaders= ''' Do a get request through a local tor or i2p instance ''' - API_VERSION = httpapi.API_VERSION + API_VERSION = onionrvalues.API_VERSION retData = False if proxyType == 'tor': if port == 0: diff --git a/onionr/setup/__init__.py b/onionr/setup/__init__.py new file mode 100644 index 00000000..8f97781c --- /dev/null +++ b/onionr/setup/__init__.py @@ -0,0 +1,3 @@ +from . import defaultpluginsetup, setupconfig +setup_default_plugins = defaultpluginsetup.setup_default_plugins +setup_config = setupconfig.setup_config \ No newline at end of file diff --git a/onionr/setup/defaultpluginsetup.py b/onionr/setup/defaultpluginsetup.py new file mode 100644 index 00000000..28b5cbc3 --- /dev/null +++ b/onionr/setup/defaultpluginsetup.py @@ -0,0 +1,21 @@ +import os, shutil +import onionrplugins as plugins, logger +def setup_default_plugins(): + # Copy default plugins into plugins folder + if not os.path.exists(plugins.get_plugins_folder()): + if os.path.exists('static-data/default-plugins/'): + names = [f for f in os.listdir("static-data/default-plugins/")] + shutil.copytree('static-data/default-plugins/', plugins.get_plugins_folder()) + + # Enable plugins + for name in names: + if not name in plugins.get_enabled_plugins(): + plugins.enable(name) + + for name in plugins.get_enabled_plugins(): + if not os.path.exists(plugins.get_plugin_data_folder(name)): + try: + os.mkdir(plugins.get_plugin_data_folder(name)) + except Exception as e: + #logger.warn('Error enabling plugin: ' + str(e), terminal=True) + plugins.disable(name, stop_event = False) \ No newline at end of file diff --git a/onionr/setupconfig.py b/onionr/setup/setupconfig.py similarity index 78% rename from onionr/setupconfig.py rename to onionr/setup/setupconfig.py index 09242815..bcd93df8 100755 --- a/onionr/setupconfig.py +++ b/onionr/setup/setupconfig.py @@ -17,8 +17,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import os, json -import config, logger +import os, json, base64 +import config, logger, netcontroller +from etc import onionrvalues from logger.settings import * def setup_config(o_inst = None): @@ -77,4 +78,15 @@ def setup_config(o_inst = None): if verbosity in map: set_level(map[verbosity]) else: - logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity) \ No newline at end of file + logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity) + + if type(config.get('client.webpassword')) is type(None): + config.set('client.webpassword', base64.b16encode(os.urandom(32)).decode('utf-8'), savefile=True) + if type(config.get('client.client.port')) is type(None): + randomPort = netcontroller.get_open_port() + config.set('client.client.port', randomPort, savefile=True) + if type(config.get('client.public.port')) is type(None): + randomPort = netcontroller.get_open_port() + config.set('client.public.port', randomPort, savefile=True) + if type(config.get('client.api_version')) is type(None): + config.set('client.api_version', onionrvalues.API_VERSION, savefile=True) \ No newline at end of file diff --git a/onionr/static-data/header.txt b/onionr/static-data/header.txt index e9366187..2703322d 100755 --- a/onionr/static-data/header.txt +++ b/onionr/static-data/header.txt @@ -18,7 +18,7 @@ P ::: :::: ::::::: :::: :::: W:: :: :: ::: :: :: :: :: :::: ::::: P ::: ::::: :::::: :::: :::: W:: :: :: ::: :: :: :: :: ::: :: ::: P :::: ::::: ::::: ::: W :::: :: :: :: ::::: :: :: :: :: P :::: :::::: :::::: :::: -P :::: :::::::::::: :::: GvPBV +P :::: :::::::::::: :::: GPB P ::::: :::::::: :::: P ::::: ::::: P :::::::::::::::: diff --git a/onionr/utils/getconsolewidth.py b/onionr/utils/getconsolewidth.py new file mode 100644 index 00000000..c5bbd6a6 --- /dev/null +++ b/onionr/utils/getconsolewidth.py @@ -0,0 +1,15 @@ +import os +def get_console_width(): + ''' + Returns an integer, the width of the terminal/cmd window + ''' + + columns = 80 + + try: + columns = int(os.popen('stty size', 'r').read().split()[1]) + except: + # if it errors, it's probably windows, so default to 80. + pass + + return columns \ No newline at end of file diff --git a/onionr/utils/gethostname.py b/onionr/utils/gethostname.py new file mode 100644 index 00000000..961fea19 --- /dev/null +++ b/onionr/utils/gethostname.py @@ -0,0 +1,10 @@ +from . import identifyhome +import filepaths +def get_hostname(): + try: + with open(identifyhome.identify_home() + '/hs/hostname', 'r') as hostname: + return hostname.read().strip() + except FileNotFoundError: + return "Not Generated" + except Exception: + return None \ No newline at end of file diff --git a/onionr/utils/logoheader.py b/onionr/utils/logoheader.py new file mode 100644 index 00000000..87ae1209 --- /dev/null +++ b/onionr/utils/logoheader.py @@ -0,0 +1,12 @@ +import sys, os +from . import readstatic +import logger +def header(message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'): + header_path = readstatic.get_static_dir() + 'header.txt' + if os.path.exists(header_path) and logger.settings.get_level() <= logger.settings.LEVEL_INFO: + with open(header_path, '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)) + + if not message is None: + logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n', terminal=True) \ No newline at end of file diff --git a/onionr/utils/readstatic.py b/onionr/utils/readstatic.py index 7ad93556..4f0be6e7 100644 --- a/onionr/utils/readstatic.py +++ b/onionr/utils/readstatic.py @@ -1,6 +1,8 @@ import os +def get_static_dir(): + return os.path.dirname(os.path.realpath(__file__)) + '/../static-data/' def read_static(file, ret_bin=False): - static_file = os.path.dirname(os.path.realpath(__file__)) + '/../static-data/' + file + static_file = get_static_dir() + file if ret_bin: mode = 'rb'