progress removing onionr.py

This commit is contained in:
Kevin Froman 2019-07-31 00:10:28 -05:00
parent e037633735
commit 6e526bf629
10 changed files with 444 additions and 61 deletions

View File

@ -0,0 +1,10 @@
import os, filepaths
def delete_run_files():
try:
os.remove(filepaths.public_API_host_file)
except FileNotFoundError:
pass
try:
os.remove(filepaths.private_API_host_file)
except FileNotFoundError:
pass

View File

@ -25,6 +25,7 @@ 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
DEVELOPMENT_MODE = True
platform = platform.system()
if platform == 'Windows':

344
onionr/onionr-old.py Executable file
View File

@ -0,0 +1,344 @@
#!/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 <https://www.gnu.org/licenses/>.
'''
import sys
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)
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)
from utils import createdirs
createdirs.create_dirs()
import os, base64, random, shutil, time, platform, signal
from threading import Thread
import config, logger, onionrplugins as plugins, onionrevents as events
import netcontroller
from onionrblockapi import Block
import onionrexceptions, communicator, setupconfig
import onionrcommands as commands # Many command definitions are here
from utils import identifyhome, hastor
from coredb import keydb
import filepaths
try:
from urllib3.contrib.socks import SOCKSProxyManager
except ImportError:
raise ImportError("You need the PySocks module (for use with socks5 proxy to use Tor)")
class Onionr:
def __init__(self):
'''
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 = onionrvalues.API_VERSION
self.userRunDir = os.getcwd() # Directory user runs the program from
self.killed = False
self.config = config
if sys.argv[0] == os.path.basename(__file__):
try:
os.chdir(sys.path[0])
except FileNotFoundError:
pass
# set data dir
self.dataDir = identifyhome.identify_home()
if not self.dataDir.endswith('/'):
self.dataDir += '/'
# Load global configuration data
data_exists = Onionr.setupConfig(self)
# 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, self)
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, onionr = self, stop_event = False)
self.communicatorInst = None
#self.deleteRunFiles()
self.clientAPIInst = '' # Client http api instance
self.publicAPIInst = '' # Public http api instance
signal.signal(signal.SIGTERM, self.exitSigterm)
# Handle commands
self.debug = False # Whole application debugging
# Get configuration
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)
self.cmds = commands.get_commands(self)
self.cmdhelp = commands.cmd_help
# initialize plugins
events.event('init', onionr = self, threaded = False)
command = ''
try:
command = sys.argv[1].lower()
except IndexError:
command = ''
finally:
self.execute(command)
os.chdir(self.userRunDir)
return
def exitSigterm(self, signum, frame):
self.killed = True
def doExport(self, bHash):
exportDir = self.dataDir + 'block-export/'
if not os.path.exists(exportDir):
if os.path.exists(self.dataDir):
os.mkdir(exportDir)
else:
logger.error('Onionr Not initialized')
data = onionrstorage.getData(bHash)
with open('%s/%s.dat' % (exportDir, bHash), 'wb') as exportFile:
exportFile.write(data)
def deleteRunFiles(self):
try:
os.remove(filepaths.public_API_host_file)
except FileNotFoundError:
pass
try:
os.remove(filepaths.private_API_host_file)
except FileNotFoundError:
pass
'''
Handle command line commands
'''
def showDetails(self):
commands.onionrstatistics.show_details(self)
def openHome(self):
commands.openwebinterface.open_home(self)
def addID(self):
commands.pubkeymanager.add_ID(self)
def changeID(self):
commands.pubkeymanager.change_ID(self)
def getCommands(self):
return self.cmds
def friendCmd(self):
'''List, add, or remove friend(s)
Changes their peer DB entry.
'''
commands.pubkeymanager.friend_command(self)
def banBlock(self):
commands.banblocks.ban_block(self)
def listConn(self):
commands.onionrstatistics.show_peers(self)
def listPeers(self):
logger.info('Peer transport address list:', terminal=True)
for i in keydb.listkeys.list_adders():
logger.info(i, terminal=True)
def getWebPassword(self):
return config.get('client.webpassword')
def printWebPassword(self):
logger.info(self.getWebPassword(), terminal=True)
def getHelp(self):
return self.cmdhelp
def addCommand(self, command, function):
self.cmds[str(command).lower()] = function
def addHelp(self, command, description):
self.cmdhelp[str(command).lower()] = str(description)
def delCommand(self, command):
return self.cmds.pop(str(command).lower(), None)
def delHelp(self, command):
return self.cmdhelp.pop(str(command).lower(), None)
def execute(self, argument):
'''
Executes a command
'''
argument = argument[argument.startswith('--') and len('--'):] # remove -- if it starts with it
# define commands
commands = self.getCommands()
command = commands.get(argument, self.notFound)
command()
def listKeys(self):
'''
Displays a list of keys (used to be called peers) (?)
'''
logger.info('%sPublic keys in database: \n%s%s' % (logger.colors.fg.lightgreen, logger.colors.fg.green, '\n'.join(keydb.listkeys.list_peers()())), terminal=True)
def addPeer(self):
'''
Adds a peer (?)
'''
commands.keyadders.add_peer(self)
def addAddress(self):
'''
Adds a Onionr node address
'''
commands.keyadders.add_address(self)
def enablePlugin(self):
'''
Enables and starts the given plugin
'''
commands.plugincommands.enable_plugin(self)
def disablePlugin(self):
'''
Disables and stops the given plugin
'''
commands.plugincommands.disable_plugin(self)
def reloadPlugin(self):
'''
Reloads (stops and starts) all plugins, or the given plugin
'''
commands.plugincommands.reload_plugin(self)
def createPlugin(self):
'''
Creates the directory structure for a plugin name
'''
commands.plugincommands.create_plugin(self)
def notFound(self):
'''
Displays a "command not found" message
'''
logger.error('Invalid command.', timestamp = False, terminal=True)
def showHelpSuggestion(self):
'''
Displays a message suggesting help
'''
logger.info('Do ' + logger.colors.bold + sys.argv[0] + ' --help' + logger.colors.reset + logger.colors.fg.green + ' for Onionr help.', terminal=True)
def start(self, input = False, override = False):
'''
Starts the Onionr daemon
'''
if config.get('general.dev_mode', False):
override = True
commands.daemonlaunch.start(self, input, override)
def setClientAPIInst(self, inst):
self.clientAPIInst = inst
def getClientApi(self):
while self.clientAPIInst == '':
time.sleep(0.5)
return self.clientAPIInst
def daemon(self):
'''
Starts the Onionr communication daemon
'''
commands.daemonlaunch.daemon(self)
def killDaemon(self):
'''
Shutdown the Onionr daemon
'''
commands.daemonlaunch.kill_daemon(self)
def showStats(self):
'''
Displays statistics and exits
'''
commands.onionrstatistics.show_stats(self)
def showHelp(self, command = None):
'''
Show help for Onionr
'''
commands.show_help(self, command)
def getFile(self):
'''
Get a file from onionr blocks
'''
commands.filecommands.getFile(self)
def addWebpage(self):
'''
Add a webpage to the onionr network
'''
self.addFile(singleBlock=True, blockType='html')
def addFile(self, singleBlock=False, blockType='bin'):
'''
Adds a file to the onionr network
'''
commands.filecommands.add_file(self, singleBlock, blockType)
if __name__ == "__main__":
Onionr()

View File

@ -44,9 +44,6 @@ def show_help(o_inst, command):
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,
'status': onionr_inst.showStats,

View File

@ -20,20 +20,22 @@
import os, time, sys, platform, sqlite3, signal
from threading import Thread
import onionr, apiservers, logger, communicator
import config, apiservers, logger, communicator
import onionrevents as events
from netcontroller import NetController
from onionrutils import localcommand
import filepaths
from coredb import daemonqueue
from etc import onionrvalues, cleanup
from onionrcrypto import getourkeypair
from utils import hastor, logoheader
from . import version
def _proper_shutdown(o_inst):
def _proper_shutdown():
localcommand.local_command('shutdown')
sys.exit(1)
def daemon(o_inst):
def daemon():
'''
Starts the Onionr communication daemon
'''
@ -46,7 +48,7 @@ def daemon(o_inst):
logger.debug('Runcheck file found on daemon start, deleting in advance.')
os.remove(filepaths.run_check_file)
Thread(target=apiservers.ClientAPI, args=(o_inst, o_inst.debug, onionr.API_VERSION), daemon=True).start()
Thread(target=apiservers.ClientAPI, args=(onionrvalues.API_VERSION), daemon=True).start()
Thread(target=apiservers.PublicAPI, args=[o_inst.getClientApi()], daemon=True).start()
apiHost = ''
@ -61,19 +63,19 @@ def daemon(o_inst):
logger.raw('', terminal=True)
# print nice header thing :)
if o_inst.config.get('general.display_header', True):
if config.get('general.display_header', True):
logoheader.header()
o_inst.version(verbosity = 5, function = logger.info)
version.version(verbosity = 5, function = logger.info)
logger.debug('Python version %s' % platform.python_version())
if o_inst._developmentMode:
if onionrvalues.DEVELOPMENT_MODE:
logger.warn('Development mode enabled', timestamp = False, terminal=True)
net = NetController(o_inst.config.get('client.public.port', 59497), apiServerIP=apiHost)
net = NetController(config.get('client.public.port', 59497), apiServerIP=apiHost)
logger.info('Tor is starting...', terminal=True)
if not net.startTor():
localcommand.local_command('shutdown')
sys.exit(1)
if len(net.myID) > 0 and o_inst.config.get('general.security_level', 1) == 0:
if len(net.myID) > 0 and config.get('general.security_level', 1) == 0:
logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID))
else:
logger.debug('.onion service disabled')
@ -82,54 +84,30 @@ def daemon(o_inst):
try:
time.sleep(1)
except KeyboardInterrupt:
_proper_shutdown(o_inst)
_proper_shutdown()
o_inst.torPort = net.socksPort
communicatorThread = Thread(target=communicator.startCommunicator, args=(o_inst, str(net.socksPort)), daemon=True)
communicatorThread.start()
events.event('daemon_start')
communicator.startCommunicator(str(net.socksPort))
while o_inst.communicatorInst is None:
time.sleep(0.1)
logger.debug('Started communicator.')
events.event('daemon_start', onionr = o_inst)
while True:
try:
time.sleep(3)
except KeyboardInterrupt:
o_inst.communicatorInst.shutdown = True
finally:
# Debug to print out used FDs (regular and net)
#proc = psutil.Process()
#print('api-files:',proc.open_files(), len(psutil.net_connections()))
# Break if communicator process ends, so we don't have left over processes
if o_inst.communicatorInst.shutdown:
break
if o_inst.killed:
break # Break out if sigterm for clean exit
signal.signal(signal.SIGINT, _ignore_sigint)
daemonqueue.daemon_queue_add('shutdown')
localcommand.local_command('shutdown')
net.killTor()
time.sleep(5) # Time to allow threads to finish, if not any "daemon" threads will be slaughtered http://docs.python.org/library/threading.html#threading.Thread.daemon
o_inst.deleteRunFiles()
return
cleanup.delete_run_files()
def _ignore_sigint(sig, frame):
'''This space intentionally left blank'''
return
def kill_daemon(o_inst):
def kill_daemon():
'''
Shutdown the Onionr daemon
'''
logger.warn('Stopping the running daemon...', timestamp = False, terminal=True)
try:
events.event('daemon_stop', onionr = o_inst)
net = NetController(o_inst.config.get('client.port', 59496))
events.event('daemon_stop')
net = NetController(config.get('client.port', 59496))
try:
daemonqueue.daemon_queue_add('shutdown')
except sqlite3.OperationalError:
@ -140,18 +118,16 @@ def kill_daemon(o_inst):
logger.error('Failed to shutdown daemon: ' + str(e), error = e, timestamp = False, terminal=True)
return
def start(o_inst, input = False, override = False):
def start(input = False, override = False):
if os.path.exists('.onionr-lock') and not override:
logger.fatal('Cannot start. Daemon is already running, or it did not exit cleanly.\n(if you are sure that there is not a daemon running, delete .onionr-lock & try again).', terminal=True)
else:
if not o_inst.debug and not o_inst._developmentMode:
if not onionrvalues.DEVELOPMENT_MODE:
lockFile = open('.onionr-lock', 'w')
lockFile.write('')
lockFile.close()
o_inst.running = True
o_inst.daemon()
o_inst.running = False
if not o_inst.debug and not o_inst._developmentMode:
daemon()
if not onionrvalues.DEVELOPMENT_MODE:
try:
os.remove('.onionr-lock')
except FileNotFoundError:

View File

@ -20,11 +20,10 @@
import os, uuid, time
import logger
from onionrblockapi import Block
import onionr
from onionrutils import checkcommunicator, mnemonickeys
from utils import sizeutils, gethostname, getconsolewidth
from coredb import blockmetadb, daemonqueue, keydb
import onionrcrypto
import onionrcrypto, config
def show_stats(o_inst):
try:
# define stats messages here
@ -43,7 +42,7 @@ def show_stats(o_inst):
# count stats
'div2' : True,
'Known Peers' : str(max(len(keydb.listkeys.list_peers()) - 1, 0)),
'Enabled Plugins' : str(len(o_inst.config.get('plugins.enabled', list()))) + ' / ' + str(len(os.listdir(o_inst.dataDir + 'plugins/'))),
'Enabled Plugins' : str(len(config.get('plugins.enabled', list()))) + ' / ' + str(len(os.listdir(o_inst.dataDir + 'plugins/'))),
'Stored Blocks' : str(totalBlocks),
'Percent Blocks Signed' : str(round(100 * signedBlocks / max(totalBlocks, 1), 2)) + '%'
}
@ -84,10 +83,10 @@ def show_stats(o_inst):
except Exception as e:
logger.error('Failed to generate statistics table. ' + str(e), error = e, timestamp = False, terminal=True)
def show_details(o_inst):
def show_details():
details = {
'Node Address' : gethostname.get_hostname(),
'Web Password' : o_inst.getWebPassword(),
'Web Password' : config.get('client.webpassword'),
'Public Key' : onionrcrypto.pub_key,
'Human-readable Public Key' : mnemonickeys.get_human_readable_ID()
}

View File

@ -17,11 +17,15 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
import argparse, sys
import sys
from etc import onionrvalues
import logger, onionrexceptions
from . import arguments, recommend
def register():
cmd = sys.argv[1]
parser = argparse.ArgumentParser(prog=onionrvalues.SCRIPT_NAME)
parser.add_argument("command", help="Onionr command to execute")
args = parser.parse_args()
print(args.start)
try:
arguments.get_func(cmd)()
except onionrexceptions.NotFound:
recommend.recommend()
sys.exit(3)

View File

@ -0,0 +1,22 @@
from .. import onionrstatistics, version, daemonlaunch
import onionrexceptions
def get_arguments():
'''This is a function because we need to be able to dynamically modify them with plugins'''
args = {
('details', 'info'): onionrstatistics.show_details,
('version'): version.version,
('start', 'daemon'): daemonlaunch.start
}
return args
def get_help():
return
def get_func(argument):
argument = argument.lower()
args = get_arguments()
for arg in args.keys(): # Iterate command alias sets
if argument in arg: # If our argument is in the current alias set, return the command function
return args[arg]
raise onionrexceptions.NotFound

View File

@ -0,0 +1,15 @@
import sys
from difflib import SequenceMatcher
import logger
from . import arguments
def recommend():
tried = sys.argv[1]
args = arguments.get_arguments()
print_message = 'Command not found:'
for key in args.keys():
for word in key:
if SequenceMatcher(None, tried, word).ratio() >= 0.75:
logger.warn('%s "%s", did you mean "%s"?' % (print_message, tried, word), terminal=True)
return
logger.error('%s "%s"' % (print_message, tried), terminal=True)

View File

@ -0,0 +1,15 @@
import platform
from utils import identifyhome
from etc import onionrvalues
import logger
def version(verbosity = 5, function = logger.info):
'''
Displays the Onionr version
'''
function('Onionr v%s (%s) (API v%s)' % (onionrvalues.ONIONR_VERSION, platform.machine(), onionrvalues.API_VERSION), terminal=True)
if verbosity >= 1:
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' % identifyhome.identify_home(), terminal=True)