diff --git a/onionr/onionr.py b/onionr/onionr.py index 532c87d5..e69de29b 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -1,457 +0,0 @@ -#!/usr/bin/env python3 -''' - Onionr - P2P Anonymous Storage Network - - Onionr is the name for both the protocol and the original/reference software. - - 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 . -''' -import sys -MIN_PY_VERSION = 6 -if sys.version_info[0] == 2 or sys.version_info[1] < MIN_PY_VERSION: - print('Error, Onionr requires Python 3.%s+' % (MIN_PY_VERSION,)) - sys.exit(1) -import os, base64, random, getpass, shutil, time, platform, datetime, re, json, getpass, sqlite3 -import webbrowser, uuid, signal -from threading import Thread -import api, core, config, logger, onionrplugins as plugins, onionrevents as events -import onionrutils -import netcontroller, onionrstorage -from netcontroller import NetController -from onionrblockapi import Block -import onionrproofs, onionrexceptions, communicator, setupconfig -from onionrusers import onionrusers -import onionrcommands as commands # Many command definitions are here - -try: - from urllib3.contrib.socks import SOCKSProxyManager -except ImportError: - raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)") - -ONIONR_TAGLINE = 'Anonymous P2P Platform - 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. - -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.userRunDir = os.getcwd() # Directory user runs the program from - self.killed = False - - if sys.argv[0] == os.path.basename(__file__): - try: - os.chdir(sys.path[0]) - except FileNotFoundError: - pass - - # 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) - - if netcontroller.torBinary() is None: - logger.error('Tor is not installed') - sys.exit(1) - - # If data folder does not exist - if not data_exists: - if not os.path.exists(self.dataDir + 'blocks/'): - os.mkdir(self.dataDir + 'blocks/') - - # 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: - plugins.disable(name, onionr = self, stop_event = False) - - self.communicatorInst = None - self.onionrCore = core.Core() - self.onionrCore.onionrInst = self - #self.deleteRunFiles() - self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore) - - 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.getOpenPort() - config.set('client.client.port', randomPort, savefile=True) - if type(config.get('client.public.port')) is type(None): - randomPort = netcontroller.getOpenPort() - print(randomPort) - config.set('client.public.port', randomPort, savefile=True) - if type(config.get('client.participate')) is type(None): - config.set('client.participate', True, savefile=True) - if type(config.get('client.api_version')) is type(None): - config.set('client.api_version', 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) - - 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)) - - 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/' - if not os.path.exists(exportDir): - if os.path.exists(self.dataDir): - os.mkdir(exportDir) - else: - logger.error('Onionr Not initialized') - data = onionrstorage.getData(self.onionrCore, bHash) - with open('%s/%s.dat' % (exportDir, bHash), 'wb') as exportFile: - exportFile.write(data) - - def deleteRunFiles(self): - try: - os.remove(self.onionrCore.publicApiHostFile) - except FileNotFoundError: - pass - try: - os.remove(self.onionrCore.privateApiHostFile) - 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 - - ''' - THIS SECTION HANDLES THE COMMANDS - ''' - - def exportBlock(self): - exportDir = self.dataDir + 'block-export/' - try: - assert self.onionrUtils.validateHash(sys.argv[2]) - except (IndexError, AssertionError): - logger.error('No valid block hash specified.') - sys.exit(1) - else: - bHash = sys.argv[2] - self.doExport(bHash) - - 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) - - 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): - try: - ban = sys.argv[2] - except IndexError: - ban = logger.readline('Enter a block hash:') - if self.onionrUtils.validateHash(ban): - if not self.onionrCore._blacklist.inBlacklist(ban): - try: - self.onionrCore._blacklist.addToDB(ban) - self.onionrCore.removeBlock(ban) - except Exception as error: - logger.error('Could not blacklist block', error=error) - else: - logger.info('Block blacklisted') - else: - logger.warn('That block is already blacklisted') - else: - logger.error('Invalid block hash') - - def listConn(self): - commands.onionrstatistics.show_peers(self) - - def listPeers(self): - logger.info('Peer transport address list:') - for i in self.onionrCore.listAdders(): - logger.info(i) - - def getWebPassword(self): - return config.get('client.webpassword') - - def printWebPassword(self): - logger.info(self.getWebPassword(), sensitive = 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 configure(self): - ''' - Displays something from the configuration file, or sets it - ''' - - if len(sys.argv) >= 4: - config.reload() - config.set(sys.argv[2], sys.argv[3], True) - logger.debug('Configuration file updated.') - elif len(sys.argv) >= 3: - config.reload() - logger.info(logger.colors.bold + sys.argv[2] + ': ' + logger.colors.reset + str(config.get(sys.argv[2], logger.colors.fg.red + 'Not set.'))) - else: - logger.info(logger.colors.bold + 'Get a value: ' + logger.colors.reset + sys.argv[0] + ' ' + sys.argv[1] + ' ') - logger.info(logger.colors.bold + 'Set a value: ' + logger.colors.reset + sys.argv[0] + ' ' + sys.argv[1] + ' ') - - 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 version(self, verbosity = 5, function = logger.info): - ''' - Displays the Onionr version - ''' - - function('Onionr v%s (%s) (API v%s)' % (ONIONR_VERSION, platform.machine(), API_VERSION)) - if verbosity >= 1: - function(ONIONR_TAGLINE) - if verbosity >= 2: - function('Running on %s %s' % (platform.platform(), platform.release())) - - def doPEX(self): - '''make communicator do pex''' - logger.info('Sending pex to command queue...') - self.onionrCore.daemonQueueAdd('pex') - - 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(self.onionrCore.listPeers()))) - - 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('Command not found.', timestamp = False) - - def showHelpSuggestion(self): - ''' - Displays a message suggesting help - ''' - 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): - ''' - Starts the Onionr daemon - ''' - 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()