diff --git a/onionr/core.py b/onionr/core.py
index 3b1bde67..f363d8bc 100644
--- a/onionr/core.py
+++ b/onionr/core.py
@@ -22,7 +22,7 @@ import sqlite3, os, sys, time, math, base64, tarfile, getpass, simplecrypt, hash
#from Crypto import Random
import netcontroller
-import onionrutils, onionrcrypto, btc
+import onionrutils, onionrcrypto, btc, onionrevents as events
if sys.version_info < (3, 6):
try:
@@ -89,10 +89,13 @@ class Core:
c.execute('INSERT INTO peers (id, name, dateSeen) VALUES(?, ?, ?);', t)
conn.commit()
conn.close()
+
return True
def addAddress(self, address):
- '''Add an address to the address database (only tor currently)'''
+ '''
+ Add an address to the address database (only tor currently)
+ '''
if self._utils.validateID(address):
conn = sqlite3.connect(self.addressDB)
c = conn.cursor()
@@ -114,12 +117,17 @@ class Core:
c.execute('INSERT INTO adders (address, type) VALUES(?, ?);', t)
conn.commit()
conn.close()
+
+ events.event('address_add', data = {'address': address}, onionr = None)
+
return True
else:
return False
def removeAddress(self, address):
- '''Remove an address from the address database'''
+ '''
+ Remove an address from the address database
+ '''
if self._utils.validateID(address):
conn = sqlite3.connect(self.addressDB)
c = conn.cursor()
@@ -127,6 +135,9 @@ class Core:
c.execute('Delete from adders where address=?;', t)
conn.commit()
conn.close()
+
+ events.event('address_remove', data = {'address': address}, onionr = None)
+
return True
else:
return False
@@ -330,6 +341,8 @@ class Core:
conn.commit()
conn.close()
+ events.event('queue_pop', data = {'data': retData}, onionr = None)
+
return retData
def daemonQueueAdd(self, command, data=''):
@@ -345,6 +358,8 @@ class Core:
conn.commit()
conn.close()
+ events.event('queue_push', data = {'command': command, 'data': data}, onionr = None)
+
return
def clearDaemonQueue(self):
@@ -354,11 +369,12 @@ class Core:
conn = sqlite3.connect(self.queueDB)
c = conn.cursor()
try:
- c.execute('delete from commands;')
+ c.execute('DELETE FROM commands;')
conn.commit()
except:
pass
conn.close()
+ events.event('queue_clear', onionr = None)
return
@@ -564,4 +580,5 @@ class Core:
announceAmount = len(nodeList)
for i in range(announceAmount):
self.daemonQueueAdd('announceNode', nodeList[i])
+ events.event('introduction', onionr = None)
return
diff --git a/onionr/default_plugin.txt b/onionr/default_plugin.txt
new file mode 100644
index 00000000..edd8247f
--- /dev/null
+++ b/onionr/default_plugin.txt
@@ -0,0 +1,41 @@
+'''
+ Default plugin template file
+ Generated on $date by $user.
+'''
+
+# Imports some useful libraries
+import logger, config
+
+def on_init(api, data = None):
+ '''
+ This event is called after Onionr is initialized, but before the command
+ inputted is executed. Could be called when daemon is starting or when
+ just the client is running.
+ '''
+
+ # Doing this makes it so that the other functions can access the api object
+ # by simply referencing the variable `pluginapi`.
+ global pluginapi
+ pluginapi = api
+
+ return
+
+def on_start(api, data = None):
+ '''
+ This event can be called for multiple reasons:
+ 1) The daemon is starting
+ 2) The user called `onionr --start-plugins` or `onionr --reload-plugins`
+ 3) For whatever reason, the plugins are reloading
+ '''
+
+ return
+
+def on_stop(api, data = None):
+ '''
+ This event can be called for multiple reasons:
+ 1) The daemon is stopping
+ 2) The user called `onionr --stop-plugins` or `onionr --reload-plugins`
+ 3) For whatever reason, the plugins are reloading
+ '''
+
+ return
diff --git a/onionr/onionr.py b/onionr/onionr.py
index 6cb15404..bcd71849 100755
--- a/onionr/onionr.py
+++ b/onionr/onionr.py
@@ -20,8 +20,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
'''
-import sys, os, base64, random, getpass, shutil, subprocess, requests, time, platform
-import api, core, config, logger, onionrplugins as plugins
+import sys, os, base64, random, getpass, shutil, subprocess, requests, time, platform, datetime, re
+import api, core, config, logger, onionrplugins as plugins, onionrevents as events
from onionrutils import OnionrUtils
from netcontroller import NetController
@@ -137,6 +137,9 @@ class Onionr:
'reloadplugin': self.reloadPlugin,
'reload-plugins': self.reloadPlugin,
'reloadplugins': self.reloadPlugin,
+ 'create-plugin': self.createPlugin,
+ 'createplugin': self.createPlugin,
+ 'plugin-create': self.createPlugin,
'listkeys': self.listKeys,
'list-keys': self.listKeys,
@@ -159,6 +162,7 @@ class Onionr:
'addaddr': self.addAddress,
'addaddress': self.addAddress,
+ 'introduce': self.onionrCore.introduceNode,
'connect': self.addAddress
}
@@ -172,14 +176,19 @@ class Onionr:
'enable-plugin': 'Enables and starts a plugin',
'disable-plugin': 'Disables and stops a plugin',
'reload-plugin': 'Reloads a plugin',
+ 'create-plugin': 'Creates directory structure for a plugin',
'add-peer': 'Adds a peer (?)',
'list-peers': 'Displays a list of peers',
'add-msg': 'Broadcasts a message to the Onionr network',
'pm': 'Adds a private message to block',
'get-pms': 'Shows private messages sent to you',
- 'gui': 'Opens a graphical interface for Onionr'
+ 'gui': 'Opens a graphical interface for Onionr',
+ 'introduce': 'Introduce your node to the public Onionr network (DAEMON MUST BE RUNNING)',
}
+ # initialize plugins
+ events.event('init', onionr = self)
+
command = ''
try:
command = sys.argv[1].lower()
@@ -238,6 +247,7 @@ class Onionr:
'''
Executes a command
'''
+
argument = argument[argument.startswith('--') and len('--'):] # remove -- if it starts with it
# define commands
@@ -256,6 +266,7 @@ class Onionr:
'''
Displays the Onionr version
'''
+
logger.info('Onionr ' + ONIONR_VERSION + ' (' + platform.machine() + ') - API v' + API_VERSION)
if verbosity >= 1:
logger.info(ONIONR_TAGLINE)
@@ -268,6 +279,7 @@ class Onionr:
'''
Create a private message and send it
'''
+
invalidID = True
while invalidID:
try:
@@ -404,6 +416,34 @@ class Onionr:
return
+ def createPlugin(self):
+ '''
+ Creates the directory structure for a plugin name
+ '''
+
+ if len(sys.argv) >= 3:
+ try:
+ plugin_name = re.sub('[^0-9a-zA-Z]+', '', str(sys.argv[2]).lower())
+
+ if not plugins.exists(plugin_name):
+ logger.info('Creating plugin \"' + plugin_name + '\"...')
+
+ os.makedirs(plugins.get_plugins_folder(plugin_name))
+ with open(plugins.get_plugins_folder(plugin_name) + '/main.py', 'a') as main:
+ main.write(open('default_plugin.txt').read().replace('$user', os.getlogin()).replace('$date', datetime.datetime.now().strftime('%Y-%m-%d')))
+
+ logger.info('Enabling plugin \"' + plugin_name + '\"...')
+ plugins.enable(plugin_name, self)
+ else:
+ logger.warn('Cannot create plugin directory structure; plugin "' + plugin_name + '" exists.')
+
+ except Exception as e:
+ logger.error('Failed to create plugin directory structure.', e)
+ else:
+ logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' ')
+
+ return
+
def notFound(self):
'''
Displays a "command not found" message
@@ -451,6 +491,7 @@ class Onionr:
time.sleep(1)
subprocess.Popen(["./communicator.py", "run", str(net.socksPort)])
logger.debug('Started communicator')
+ events.event('daemon_start', onionr = self)
api.API(self.debug)
return
@@ -461,6 +502,7 @@ class Onionr:
'''
logger.warn('Killing the running daemon')
+ events.event('daemon_stop', onionr = self)
net = NetController(config.get('client')['port'])
try:
self.onionrUtils.localCommand('shutdown')
diff --git a/onionr/onionrevents.py b/onionr/onionrevents.py
index 9b386a31..61005b98 100644
--- a/onionr/onionrevents.py
+++ b/onionr/onionrevents.py
@@ -20,19 +20,20 @@
import config, logger, onionrplugins as plugins, onionrpluginapi as pluginapi
-def get_pluginapi(onionr):
- return pluginapi.PluginAPI(onionr)
+def get_pluginapi(onionr, data):
+ return pluginapi.pluginapi(onionr, data)
-def event(event_name, data = None, onionr = None):
+def event(event_name, data = {}, onionr = None):
'''
Calls an event on all plugins (if defined)
'''
for plugin in plugins.get_enabled_plugins():
try:
- call(plugins.get_plugin(plugin), event_name, data, self.get_pluginapi(onionr))
- except:
+ call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data))
+ except Exception as e:
logger.warn('Event \"' + event_name + '\" failed for plugin \"' + plugin + '\".')
+ logger.debug(str(e))
def call(plugin, event_name, data = None, pluginapi = None):
'''
@@ -45,12 +46,12 @@ def call(plugin, event_name, data = None, pluginapi = None):
# TODO: Use multithreading perhaps?
if hasattr(plugin, attribute):
- logger.debug('Calling event ' + str(event_name))
- getattr(plugin, attribute)(pluginapi, data)
+ #logger.debug('Calling event ' + str(event_name))
+ getattr(plugin, attribute)(pluginapi)
return True
- except:
- logger.warn('Failed to call event ' + str(event_name) + ' on module.')
+ except Exception as e:
+ logger.debug(str(e))
return False
else:
return True
diff --git a/onionr/onionrpluginapi.py b/onionr/onionrpluginapi.py
index 67d37694..c6d68f31 100644
--- a/onionr/onionrpluginapi.py
+++ b/onionr/onionrpluginapi.py
@@ -20,131 +20,135 @@
import onionrplugins as plugins, logger
+class DaemonAPI:
+ def __init__(self, pluginapi):
+ self.pluginapi = pluginapi
+
+ def start(self):
+ self.pluginapi.get_onionr().daemon()
+
+ return
+
+ def stop(self):
+ self.pluginapi.get_onionr().killDaemon()
+
+ return
+
+ def queue(self, command, data = ''):
+ self.pluginapi.get_core().daemonQueueAdd(command, data)
+
+ return
+
+ def local_command(self, command):
+ self.pluginapi.get_utils().localCommand(self, command)
+
+ return
+
+ def queue_pop(self):
+ return self.get_core().daemonQueue()
+
class PluginAPI:
- def __init__(self, onionr):
+ def __init__(self, pluginapi):
+ self.pluginapi = pluginapi
+
+ def start(self, name):
+ plugins.start(name)
+
+ def stop(self, name):
+ plugins.stop(name)
+
+ def reload(self, name):
+ plugins.reload(name)
+
+ def enable(self, name):
+ plugins.enable(name)
+
+ def disable(self, name):
+ plugins.disable(name)
+
+ def is_enabled(self, name):
+ return plugins.is_enabled(name)
+
+ def get_enabled_plugins(self):
+ return plugins.get_enabled_plugins()
+
+class CommandAPI:
+ def __init__(self, pluginapi):
+ self.pluginapi = pluginapi
+
+ def register(self, names, call = None):
+ if isinstance(names, str):
+ names = [names]
+
+ for name in names:
+ self.pluginapi.get_onionr().addCommand(name, call)
+
+ return
+
+ def unregister(self, names):
+ if isinstance(names, str):
+ names = [names]
+
+ for name in names:
+ self.pluginapi.get_onionr().delCommand(name)
+
+ return
+
+ def register_help(self, names, description):
+ if isinstance(names, str):
+ names = [names]
+
+ for name in names:
+ self.pluginapi.get_onionr().addHelp(name, description)
+
+ return
+
+ def unregister_help(self, names):
+ if isinstance(names, str):
+ names = [names]
+
+ for name in names:
+ self.pluginapi.get_onionr().delHelp(name)
+
+ return
+
+ def call(self, name):
+ self.pluginapi.get_onionr().execute(name)
+
+ return
+
+ def get_commands(self):
+ return self.pluginapi.get_onionr().getCommands()
+
+class pluginapi:
+ def __init__(self, onionr, data):
self.onionr = onionr
-
+ self.data = data
+
self.daemon = DaemonAPI(self)
- self.plugin = PluginAPI(self)
- self.command = CommandAPI(self)
-
+ self.plugins = PluginAPI(self)
+ self.commands = CommandAPI(self)
+
def get_onionr(self):
return self.onionr
-
+
+ def get_data(self):
+ return self.data
+
def get_core(self):
return self.get_onionr().onionrCore
-
+
def get_utils(self):
return self.get_onionr().onionrUtils
-
+
def get_daemonapi(self):
return self.daemon
-
+
def get_pluginapi(self):
- return self.plugin
-
+ return self.plugins
+
def get_commandapi(self):
- return self.command
-
+ return self.commands
+
def is_development_mode(self):
return self.get_onionr()._developmentMode
-
- class DaemonAPI:
- def __init__(self, pluginapi):
- self.pluginapi = pluginapi
-
- def start(self):
- self.pluginapi.get_onionr().daemon()
-
- return
-
- def stop(self):
- self.pluginapi.get_onionr().killDaemon()
-
- return
-
- def queue(self, command, data = ''):
- self.pluginapi.get_core().daemonQueueAdd(command, data)
-
- return
-
- def local_command(self, command):
- self.pluginapi.get_utils().localCommand(self, command)
-
- return
-
- def queue_pop(self):
- return self.get_core().daemonQueue()
-
- class PluginAPI:
- def __init__(self, pluginapi):
- self.pluginapi = pluginapi
-
- def start(self, name):
- plugins.start(name)
-
- def stop(self, name):
- plugins.stop(name)
-
- def reload(self, name):
- plugins.reload(name)
-
- def enable(self, name):
- plugins.enable(name)
-
- def disable(self, name):
- plugins.disable(name)
-
- def is_enabled(self, name):
- return plugins.is_enabled(name)
-
- def get_enabled_plugins(self):
- return plugins.get_enabled_plugins()
-
- class CommandAPI:
- def __init__(self, pluginapi):
- self.pluginapi = pluginapi
-
- def register(self, names, call = None):
- if isinstance(names, str):
- names = [names]
-
- for name in names:
- self.pluginapi.get_onionr().addCommand(name, call)
-
- return
-
- def unregister(self, names):
- if isinstance(names, str):
- names = [names]
-
- for name in names:
- self.pluginapi.get_onionr().delCommand(name)
-
- return
-
- def register_help(self, names, description):
- if isinstance(names, str):
- names = [names]
-
- for name in names:
- self.pluginapi.get_onionr().addHelp(name, description)
-
- return
-
- def unregister_help(self, names):
- if isinstance(names, str):
- names = [names]
-
- for name in names:
- self.pluginapi.get_onionr().delHelp(name)
-
- return
-
- def call(self, name):
- self.pluginapi.get_onionr().execute(name)
-
- return
-
- def get_commands(self):
- return self.pluginapi.get_onionr().getCommands()
diff --git a/onionr/onionrplugins.py b/onionr/onionrplugins.py
index f75836cd..13ca3b95 100644
--- a/onionr/onionrplugins.py
+++ b/onionr/onionrplugins.py
@@ -225,5 +225,5 @@ def check():
if not os.path.exists(os.path.dirname(get_plugins_folder())):
logger.debug('Generating plugin data folder...')
os.makedirs(os.path.dirname(get_plugins_folder()))
-
+
return
diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py
index 142d2666..634770c4 100644
--- a/onionr/onionrutils.py
+++ b/onionr/onionrutils.py
@@ -129,7 +129,7 @@ class OnionrUtils:
logger.error('Failed to read my address.', error=error)
return ''
- def localCommand(self, command):
+ def localCommand(self, command, silent = True):
'''
Send a command to the local http API server, securely. Intended for local clients, DO NOT USE for remote peers.
'''
@@ -140,7 +140,8 @@ class OnionrUtils:
try:
retData = requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config.get('client')['port']) + '/client/?action=' + command + '&token=' + str(config.get('client')['client_hmac']) + '&timingToken=' + self.timingToken).text
except Exception as error:
- logger.error('Failed to make local request (command: ' + str(command) + ').', error=error)
+ if not silent:
+ logger.error('Failed to make local request (command: ' + str(command) + ').', error=error)
retData = False
return retData
diff --git a/onionr/tests.py b/onionr/tests.py
index 74027b87..122433bf 100755
--- a/onionr/tests.py
+++ b/onionr/tests.py
@@ -134,7 +134,7 @@ class OnionrTests(unittest.TestCase):
if not onionrplugins.exists('test'):
os.makedirs(onionrplugins.get_plugins_folder('test'))
with open(onionrplugins.get_plugins_folder('test') + '/main.py', 'a') as main:
- main.write("print('Running')\n\ndef on_test(onionr = None, data = None):\n print('received test event!')\n return True\n\ndef on_start(onionr = None, data = None):\n print('start event called')\n\ndef on_stop(onionr = None, data = None):\n print('stop event called')\n\ndef on_enable(onionr = None, data = None):\n print('enable event called')\n\ndef on_disable(onionr = None, data = None):\n print('disable event called')\n")
+ main.write("print('Running')\n\ndef on_test(pluginapi, data = None):\n print('received test event!')\n return True\n\ndef on_start(pluginapi, data = None):\n print('start event called')\n\ndef on_stop(pluginapi, data = None):\n print('stop event called')\n\ndef on_enable(pluginapi, data = None):\n print('enable event called')\n\ndef on_disable(pluginapi, data = None):\n print('disable event called')\n")
onionrplugins.enable('test')
try:
@@ -152,7 +152,7 @@ class OnionrTests(unittest.TestCase):
if not onionrplugins.exists('test'):
os.makedirs(onionrplugins.get_plugins_folder('test'))
with open(onionrplugins.get_plugins_folder('test') + '/main.py', 'a') as main:
- main.write("print('Running')\n\ndef on_test(onionr = None, data = None):\n print('received test event!')\n return True\n\ndef on_start(onionr = None, data = None):\n print('start event called')\n\ndef on_stop(onionr = None, data = None):\n print('stop event called')\n\ndef on_enable(onionr = None, data = None):\n print('enable event called')\n\ndef on_disable(onionr = None, data = None):\n print('disable event called')\n")
+ main.write("print('Running')\n\ndef on_test(pluginapi, data = None):\n print('received test event!')\n return True\n\ndef on_start(pluginapi, data = None):\n print('start event called')\n\ndef on_stop(pluginapi, data = None):\n print('stop event called')\n\ndef on_enable(pluginapi, data = None):\n print('enable event called')\n\ndef on_disable(pluginapi, data = None):\n print('disable event called')\n")
onionrplugins.enable('test')
try:
@@ -171,7 +171,7 @@ class OnionrTests(unittest.TestCase):
if not plugins.exists('test'):
os.makedirs(plugins.get_plugins_folder('test'))
with open(plugins.get_plugins_folder('test') + '/main.py', 'a') as main:
- main.write("print('Running')\n\ndef on_test(onionr = None, data = None):\n print('received test event!')\n return True\n\ndef on_start(onionr = None, data = None):\n print('start event called')\n\ndef on_stop(onionr = None, data = None):\n print('stop event called')\n\ndef on_enable(onionr = None, data = None):\n print('enable event called')\n\ndef on_disable(onionr = None, data = None):\n print('disable event called')\n")
+ main.write("print('Running')\n\ndef on_test(pluginapi, data = None):\n print('received test event!')\n return True\n\ndef on_start(pluginapi, data = None):\n print('start event called')\n\ndef on_stop(pluginapi, data = None):\n print('stop event called')\n\ndef on_enable(pluginapi, data = None):\n print('enable event called')\n\ndef on_disable(pluginapi, data = None):\n print('disable event called')\n")
plugins.enable('test')