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'