more refactoring and secured requirements.txt
This commit is contained in:
parent
236edac257
commit
1562848999
@ -58,7 +58,7 @@ Encrypted, metadata-masking mail application.
|
|||||||
|
|
||||||
The following applies to Ubuntu Bionic. Other distros may have different package or command names.
|
The following applies to Ubuntu Bionic. Other distros may have different package or command names.
|
||||||
|
|
||||||
* Have python3.5+, python3-pip, Tor (daemon, not browser) installed (python3-dev recommended)
|
* Have python3.6+, python3-pip, Tor (daemon, not browser) installed (python3-dev recommended)
|
||||||
* Clone the git repo: `$ git clone https://gitlab.com/beardog/onionr`
|
* Clone the git repo: `$ git clone https://gitlab.com/beardog/onionr`
|
||||||
* cd into install direction: `$ cd onionr/`
|
* cd into install direction: `$ cd onionr/`
|
||||||
* Install the Python dependencies ([virtualenv strongly recommended](https://virtualenv.pypa.io/en/stable/userguide/)): `$ pip3 install -r requirements.txt`
|
* Install the Python dependencies ([virtualenv strongly recommended](https://virtualenv.pypa.io/en/stable/userguide/)): `$ pip3 install -r requirements.txt`
|
||||||
|
274
onionr/onionr.py
274
onionr/onionr.py
@ -33,7 +33,7 @@ import onionrutils
|
|||||||
import netcontroller, onionrstorage
|
import netcontroller, onionrstorage
|
||||||
from netcontroller import NetController
|
from netcontroller import NetController
|
||||||
from onionrblockapi import Block
|
from onionrblockapi import Block
|
||||||
import onionrproofs, onionrexceptions, communicator
|
import onionrproofs, onionrexceptions, communicator, setupconfig
|
||||||
from onionrusers import onionrusers
|
from onionrusers import onionrusers
|
||||||
import onionrcommands as commands # Many command definitions are here
|
import onionrcommands as commands # Many command definitions are here
|
||||||
|
|
||||||
@ -148,9 +148,15 @@ class Onionr:
|
|||||||
def exitSigterm(self, signum, frame):
|
def exitSigterm(self, signum, frame):
|
||||||
self.killed = True
|
self.killed = True
|
||||||
|
|
||||||
'''
|
def setupConfig(dataDir, self = None):
|
||||||
THIS SECTION HANDLES THE COMMANDS
|
setupconfig.setup_config(dataDir, self)
|
||||||
'''
|
|
||||||
|
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))
|
||||||
|
logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
|
||||||
|
|
||||||
def doExport(self, bHash):
|
def doExport(self, bHash):
|
||||||
exportDir = self.dataDir + 'block-export/'
|
exportDir = self.dataDir + 'block-export/'
|
||||||
@ -163,6 +169,44 @@ class Onionr:
|
|||||||
with open('%s/%s.dat' % (exportDir, bHash), 'wb') as exportFile:
|
with open('%s/%s.dat' % (exportDir, bHash), 'wb') as exportFile:
|
||||||
exportFile.write(data)
|
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):
|
def exportBlock(self):
|
||||||
exportDir = self.dataDir + 'block-export/'
|
exportDir = self.dataDir + 'block-export/'
|
||||||
try:
|
try:
|
||||||
@ -195,26 +239,6 @@ class Onionr:
|
|||||||
'''
|
'''
|
||||||
commands.pubkeymanager.friend_command(self)
|
commands.pubkeymanager.friend_command(self)
|
||||||
|
|
||||||
def deleteRunFiles(self):
|
|
||||||
try:
|
|
||||||
os.remove(self.onionrCore.publicApiHostFile)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
os.remove(self.onionrCore.privateApiHostFile)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def deleteRunFiles(self):
|
|
||||||
try:
|
|
||||||
os.remove(self.onionrCore.publicApiHostFile)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
os.remove(self.onionrCore.privateApiHostFile)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def banBlock(self):
|
def banBlock(self):
|
||||||
try:
|
try:
|
||||||
ban = sys.argv[2]
|
ban = sys.argv[2]
|
||||||
@ -233,7 +257,6 @@ class Onionr:
|
|||||||
logger.warn('That block is already blacklisted')
|
logger.warn('That block is already blacklisted')
|
||||||
else:
|
else:
|
||||||
logger.error('Invalid block hash')
|
logger.error('Invalid block hash')
|
||||||
return
|
|
||||||
|
|
||||||
def listConn(self):
|
def listConn(self):
|
||||||
commands.onionrstatistics.show_peers(self)
|
commands.onionrstatistics.show_peers(self)
|
||||||
@ -293,12 +316,6 @@ class Onionr:
|
|||||||
command = commands.get(argument, self.notFound)
|
command = commands.get(argument, self.notFound)
|
||||||
command()
|
command()
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
'''
|
|
||||||
THIS SECTION DEFINES THE COMMANDS
|
|
||||||
'''
|
|
||||||
|
|
||||||
def version(self, verbosity = 5, function = logger.info):
|
def version(self, verbosity = 5, function = logger.info):
|
||||||
'''
|
'''
|
||||||
Displays the Onionr version
|
Displays the Onionr version
|
||||||
@ -310,8 +327,6 @@ class Onionr:
|
|||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
function('Running on %s %s' % (platform.platform(), platform.release()))
|
function('Running on %s %s' % (platform.platform(), platform.release()))
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def doPEX(self):
|
def doPEX(self):
|
||||||
'''make communicator do pex'''
|
'''make communicator do pex'''
|
||||||
logger.info('Sending pex to command queue...')
|
logger.info('Sending pex to command queue...')
|
||||||
@ -321,126 +336,43 @@ class Onionr:
|
|||||||
'''
|
'''
|
||||||
Displays a list of keys (used to be called peers) (?)
|
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())))
|
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):
|
def addPeer(self):
|
||||||
'''
|
'''
|
||||||
Adds a peer (?)
|
Adds a peer (?)
|
||||||
'''
|
'''
|
||||||
try:
|
commands.keyadders.add_peer(self)
|
||||||
newPeer = sys.argv[2]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if self.onionrUtils.hasKey(newPeer):
|
|
||||||
logger.info('We already have that key')
|
|
||||||
return
|
|
||||||
logger.info("Adding peer: " + logger.colors.underline + newPeer)
|
|
||||||
try:
|
|
||||||
if self.onionrCore.addPeer(newPeer):
|
|
||||||
logger.info('Successfully added key')
|
|
||||||
except AssertionError:
|
|
||||||
logger.error('Failed to add key')
|
|
||||||
return
|
|
||||||
|
|
||||||
def addAddress(self):
|
def addAddress(self):
|
||||||
'''
|
'''
|
||||||
Adds a Onionr node address
|
Adds a Onionr node address
|
||||||
'''
|
'''
|
||||||
|
commands.keyadders.add_address(self)
|
||||||
try:
|
|
||||||
newAddress = sys.argv[2]
|
|
||||||
newAddress = newAddress.replace('http:', '').replace('/', '')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
logger.info("Adding address: " + logger.colors.underline + newAddress)
|
|
||||||
if self.onionrCore.addAddress(newAddress):
|
|
||||||
logger.info("Successfully added address.")
|
|
||||||
else:
|
|
||||||
logger.warn("Unable to add address.")
|
|
||||||
return
|
|
||||||
|
|
||||||
def enablePlugin(self):
|
def enablePlugin(self):
|
||||||
'''
|
'''
|
||||||
Enables and starts the given plugin
|
Enables and starts the given plugin
|
||||||
'''
|
'''
|
||||||
|
commands.plugincommands.enable_plugin(self)
|
||||||
if len(sys.argv) >= 3:
|
|
||||||
plugin_name = sys.argv[2]
|
|
||||||
logger.info('Enabling plugin "%s"...' % plugin_name)
|
|
||||||
plugins.enable(plugin_name, self)
|
|
||||||
else:
|
|
||||||
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def disablePlugin(self):
|
def disablePlugin(self):
|
||||||
'''
|
'''
|
||||||
Disables and stops the given plugin
|
Disables and stops the given plugin
|
||||||
'''
|
'''
|
||||||
|
commands.plugincommands.disable_plugin(self)
|
||||||
if len(sys.argv) >= 3:
|
|
||||||
plugin_name = sys.argv[2]
|
|
||||||
logger.info('Disabling plugin "%s"...' % plugin_name)
|
|
||||||
plugins.disable(plugin_name, self)
|
|
||||||
else:
|
|
||||||
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def reloadPlugin(self):
|
def reloadPlugin(self):
|
||||||
'''
|
'''
|
||||||
Reloads (stops and starts) all plugins, or the given plugin
|
Reloads (stops and starts) all plugins, or the given plugin
|
||||||
'''
|
'''
|
||||||
|
commands.plugincommands.reload_plugin(self)
|
||||||
if len(sys.argv) >= 3:
|
|
||||||
plugin_name = sys.argv[2]
|
|
||||||
logger.info('Reloading plugin "%s"...' % plugin_name)
|
|
||||||
plugins.stop(plugin_name, self)
|
|
||||||
plugins.start(plugin_name, self)
|
|
||||||
else:
|
|
||||||
logger.info('Reloading all plugins...')
|
|
||||||
plugins.reload(self)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def createPlugin(self):
|
def createPlugin(self):
|
||||||
'''
|
'''
|
||||||
Creates the directory structure for a plugin name
|
Creates the directory structure for a plugin name
|
||||||
'''
|
'''
|
||||||
|
commands.plugincommands.create_plugin(self)
|
||||||
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 "%s"...' % plugin_name)
|
|
||||||
|
|
||||||
os.makedirs(plugins.get_plugins_folder(plugin_name))
|
|
||||||
with open(plugins.get_plugins_folder(plugin_name) + '/main.py', 'a') as main:
|
|
||||||
contents = ''
|
|
||||||
with open('static-data/default_plugin.py', 'rb') as file:
|
|
||||||
contents = file.read().decode()
|
|
||||||
|
|
||||||
# TODO: Fix $user. os.getlogin() is B U G G Y
|
|
||||||
main.write(contents.replace('$user', 'some random developer').replace('$date', datetime.datetime.now().strftime('%Y-%m-%d')).replace('$name', plugin_name))
|
|
||||||
|
|
||||||
with open(plugins.get_plugins_folder(plugin_name) + '/info.json', 'a') as main:
|
|
||||||
main.write(json.dumps({'author' : 'anonymous', 'description' : 'the default description of the plugin', 'version' : '1.0'}))
|
|
||||||
|
|
||||||
logger.info('Enabling plugin "%s"...' % plugin_name)
|
|
||||||
plugins.enable(plugin_name, self)
|
|
||||||
else:
|
|
||||||
logger.warn('Cannot create plugin directory structure; plugin "%s" exists.' % plugin_name)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Failed to create plugin directory structure.', e)
|
|
||||||
else:
|
|
||||||
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def notFound(self):
|
def notFound(self):
|
||||||
'''
|
'''
|
||||||
@ -494,30 +426,6 @@ class Onionr:
|
|||||||
'''
|
'''
|
||||||
commands.show_help(self, command)
|
commands.show_help(self, command)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def getFile(self):
|
def getFile(self):
|
||||||
'''
|
'''
|
||||||
Get a file from onionr blocks
|
Get a file from onionr blocks
|
||||||
@ -536,79 +444,5 @@ class Onionr:
|
|||||||
'''
|
'''
|
||||||
commands.filecommands.add_file(self, singleBlock, blockType)
|
commands.filecommands.add_file(self, singleBlock, blockType)
|
||||||
|
|
||||||
def setupConfig(dataDir, self = None):
|
|
||||||
data_exists = os.path.exists(dataDir)
|
|
||||||
|
|
||||||
if not data_exists:
|
|
||||||
os.mkdir(dataDir)
|
|
||||||
|
|
||||||
if os.path.exists('static-data/default_config.json'):
|
|
||||||
# this is the default config, it will be overwritten if a config file already exists. Else, it saves it
|
|
||||||
with open('static-data/default_config.json', 'r') as configReadIn:
|
|
||||||
config.set_config(json.loads(configReadIn.read()))
|
|
||||||
else:
|
|
||||||
# the default config file doesn't exist, try hardcoded config
|
|
||||||
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
|
|
||||||
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
|
|
||||||
if not data_exists:
|
|
||||||
config.save()
|
|
||||||
config.reload() # this will read the configuration file into memory
|
|
||||||
|
|
||||||
settings = 0b000
|
|
||||||
if config.get('log.console.color', True):
|
|
||||||
settings = settings | logger.USE_ANSI
|
|
||||||
if config.get('log.console.output', True):
|
|
||||||
settings = settings | logger.OUTPUT_TO_CONSOLE
|
|
||||||
if config.get('log.file.output', True):
|
|
||||||
settings = settings | logger.OUTPUT_TO_FILE
|
|
||||||
logger.set_settings(settings)
|
|
||||||
|
|
||||||
if not self is None:
|
|
||||||
if str(config.get('general.dev_mode', True)).lower() == 'true':
|
|
||||||
self._developmentMode = True
|
|
||||||
logger.set_level(logger.LEVEL_DEBUG)
|
|
||||||
else:
|
|
||||||
self._developmentMode = False
|
|
||||||
logger.set_level(logger.LEVEL_INFO)
|
|
||||||
|
|
||||||
verbosity = str(config.get('log.verbosity', 'default')).lower().strip()
|
|
||||||
if not verbosity in ['default', 'null', 'none', 'nil']:
|
|
||||||
map = {
|
|
||||||
str(logger.LEVEL_DEBUG) : logger.LEVEL_DEBUG,
|
|
||||||
'verbose' : logger.LEVEL_DEBUG,
|
|
||||||
'debug' : logger.LEVEL_DEBUG,
|
|
||||||
str(logger.LEVEL_INFO) : logger.LEVEL_INFO,
|
|
||||||
'info' : logger.LEVEL_INFO,
|
|
||||||
'information' : logger.LEVEL_INFO,
|
|
||||||
str(logger.LEVEL_WARN) : logger.LEVEL_WARN,
|
|
||||||
'warn' : logger.LEVEL_WARN,
|
|
||||||
'warning' : logger.LEVEL_WARN,
|
|
||||||
'warnings' : logger.LEVEL_WARN,
|
|
||||||
str(logger.LEVEL_ERROR) : logger.LEVEL_ERROR,
|
|
||||||
'err' : logger.LEVEL_ERROR,
|
|
||||||
'error' : logger.LEVEL_ERROR,
|
|
||||||
'errors' : logger.LEVEL_ERROR,
|
|
||||||
str(logger.LEVEL_FATAL) : logger.LEVEL_FATAL,
|
|
||||||
'fatal' : logger.LEVEL_FATAL,
|
|
||||||
str(logger.LEVEL_IMPORTANT) : logger.LEVEL_IMPORTANT,
|
|
||||||
'silent' : logger.LEVEL_IMPORTANT,
|
|
||||||
'quiet' : logger.LEVEL_IMPORTANT,
|
|
||||||
'important' : logger.LEVEL_IMPORTANT
|
|
||||||
}
|
|
||||||
|
|
||||||
if verbosity in map:
|
|
||||||
logger.set_level(map[verbosity])
|
|
||||||
else:
|
|
||||||
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
|
|
||||||
|
|
||||||
return data_exists
|
|
||||||
|
|
||||||
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))
|
|
||||||
logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Onionr()
|
Onionr()
|
||||||
|
@ -18,9 +18,26 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import webbrowser
|
import webbrowser, sys
|
||||||
import logger
|
import logger
|
||||||
from . import pubkeymanager, onionrstatistics, daemonlaunch, filecommands
|
from . import pubkeymanager, onionrstatistics, daemonlaunch, filecommands, plugincommands, keyadders
|
||||||
|
|
||||||
|
def show_help(o_inst, command):
|
||||||
|
|
||||||
|
helpmenu = o_inst.getHelp()
|
||||||
|
|
||||||
|
if command is None and len(sys.argv) >= 3:
|
||||||
|
for cmd in sys.argv[2:]:
|
||||||
|
o_inst.showHelp(cmd)
|
||||||
|
elif not command is None:
|
||||||
|
if command.lower() in helpmenu:
|
||||||
|
logger.info(logger.colors.bold + command + logger.colors.reset + logger.colors.fg.blue + ' : ' + logger.colors.reset + helpmenu[command.lower()], timestamp = False)
|
||||||
|
else:
|
||||||
|
logger.warn(logger.colors.bold + command + logger.colors.reset + logger.colors.fg.blue + ' : ' + logger.colors.reset + 'No help menu entry was found', timestamp = False)
|
||||||
|
else:
|
||||||
|
o_inst.version(0)
|
||||||
|
for command, helpmessage in helpmenu.items():
|
||||||
|
o_inst.showHelp(command)
|
||||||
|
|
||||||
def open_home(o_inst):
|
def open_home(o_inst):
|
||||||
try:
|
try:
|
||||||
@ -28,7 +45,7 @@ def open_home(o_inst):
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.error('Onionr seems to not be running (could not get api host)')
|
logger.error('Onionr seems to not be running (could not get api host)')
|
||||||
else:
|
else:
|
||||||
url = 'http://%s/#%s' % (url, config.get('client.webpassword'))
|
url = 'http://%s/#%s' % (url, o_inst.onionrCore.config.get('client.webpassword'))
|
||||||
print('If Onionr does not open automatically, use this URL:', url)
|
print('If Onionr does not open automatically, use this URL:', url)
|
||||||
webbrowser.open_new_tab(url)
|
webbrowser.open_new_tab(url)
|
||||||
|
|
||||||
|
@ -103,3 +103,20 @@ def kill_daemon(o_inst):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to shutdown daemon.', error = e, timestamp = False)
|
logger.error('Failed to shutdown daemon.', error = e, timestamp = False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def start(o_inst, 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).')
|
||||||
|
else:
|
||||||
|
if not o_inst.debug and not o_inst._developmentMode:
|
||||||
|
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:
|
||||||
|
try:
|
||||||
|
os.remove('.onionr-lock')
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
@ -1,5 +1,6 @@
|
|||||||
import base64, sys, os
|
import base64, sys, os
|
||||||
import logger
|
import logger
|
||||||
|
from onionrblockapi import Block
|
||||||
def add_file(o_inst, singleBlock=False, blockType='bin'):
|
def add_file(o_inst, singleBlock=False, blockType='bin'):
|
||||||
'''
|
'''
|
||||||
Adds a file to the onionr network
|
Adds a file to the onionr network
|
||||||
@ -22,3 +23,27 @@ def add_file(o_inst, singleBlock=False, blockType='bin'):
|
|||||||
logger.error('Failed to save file in block.', timestamp = False)
|
logger.error('Failed to save file in block.', timestamp = False)
|
||||||
else:
|
else:
|
||||||
logger.error('%s add-file <filename>' % sys.argv[0], timestamp = False)
|
logger.error('%s add-file <filename>' % sys.argv[0], timestamp = False)
|
||||||
|
|
||||||
|
def getFile(o_inst):
|
||||||
|
'''
|
||||||
|
Get a file from onionr blocks
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
fileName = sys.argv[2]
|
||||||
|
bHash = sys.argv[3]
|
||||||
|
except IndexError:
|
||||||
|
logger.error("Syntax %s %s" % (sys.argv[0], '/path/to/filename <blockhash>'))
|
||||||
|
else:
|
||||||
|
logger.info(fileName)
|
||||||
|
|
||||||
|
contents = None
|
||||||
|
if os.path.exists(fileName):
|
||||||
|
logger.error("File already exists")
|
||||||
|
return
|
||||||
|
if not o_inst.onionrUtils.validateHash(bHash):
|
||||||
|
logger.error('Block hash is invalid')
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(fileName, 'wb') as myFile:
|
||||||
|
myFile.write(base64.b64decode(Block(bHash, core=o_inst.onionrCore).bcontent))
|
||||||
|
return
|
31
onionr/onionrcommands/keyadders.py
Normal file
31
onionr/onionrcommands/keyadders.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import sys
|
||||||
|
import logger
|
||||||
|
|
||||||
|
def add_peer(o_inst):
|
||||||
|
try:
|
||||||
|
newPeer = sys.argv[2]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if o_inst.onionrUtils.hasKey(newPeer):
|
||||||
|
logger.info('We already have that key')
|
||||||
|
return
|
||||||
|
logger.info("Adding peer: " + logger.colors.underline + newPeer)
|
||||||
|
try:
|
||||||
|
if o_inst.onionrCore.addPeer(newPeer):
|
||||||
|
logger.info('Successfully added key')
|
||||||
|
except AssertionError:
|
||||||
|
logger.error('Failed to add key')
|
||||||
|
|
||||||
|
def add_address(o_inst):
|
||||||
|
try:
|
||||||
|
newAddress = sys.argv[2]
|
||||||
|
newAddress = newAddress.replace('http:', '').replace('/', '')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.info("Adding address: " + logger.colors.underline + newAddress)
|
||||||
|
if self.onionrCore.addAddress(newAddress):
|
||||||
|
logger.info("Successfully added address.")
|
||||||
|
else:
|
||||||
|
logger.warn("Unable to add address.")
|
@ -17,7 +17,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
'''
|
'''
|
||||||
import os
|
import os, uuid, time
|
||||||
import logger, onionrutils
|
import logger, onionrutils
|
||||||
from onionrblockapi import Block
|
from onionrblockapi import Block
|
||||||
import onionr
|
import onionr
|
||||||
@ -91,3 +91,20 @@ def show_details(o_inst):
|
|||||||
|
|
||||||
for detail in details:
|
for detail in details:
|
||||||
logger.info('%s%s: \n%s%s\n' % (logger.colors.fg.lightgreen, detail, logger.colors.fg.green, details[detail]), sensitive = True)
|
logger.info('%s%s: \n%s%s\n' % (logger.colors.fg.lightgreen, detail, logger.colors.fg.green, details[detail]), sensitive = True)
|
||||||
|
|
||||||
|
def show_peers(o_inst):
|
||||||
|
randID = str(uuid.uuid4())
|
||||||
|
o_inst.onionrCore.daemonQueueAdd('connectedPeers', responseID=randID)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
time.sleep(3)
|
||||||
|
peers = o_inst.onionrCore.daemonQueueGetResponse(randID)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
break
|
||||||
|
if not type(peers) is None:
|
||||||
|
if peers not in ('', 'failure', None):
|
||||||
|
if peers != False:
|
||||||
|
print(peers)
|
||||||
|
else:
|
||||||
|
print('Daemon probably not running. Unable to list connected peers.')
|
||||||
|
break
|
68
onionr/onionrcommands/plugincommands.py
Normal file
68
onionr/onionrcommands/plugincommands.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import sys
|
||||||
|
import logger, onionrplugins as plugins
|
||||||
|
|
||||||
|
def enable_plugin(o_inst):
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
plugin_name = sys.argv[2]
|
||||||
|
logger.info('Enabling plugin "%s"...' % plugin_name)
|
||||||
|
plugins.enable(plugin_name, o_inst)
|
||||||
|
else:
|
||||||
|
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
||||||
|
|
||||||
|
def disable_plugin(o_inst):
|
||||||
|
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
plugin_name = sys.argv[2]
|
||||||
|
logger.info('Disabling plugin "%s"...' % plugin_name)
|
||||||
|
plugins.disable(plugin_name, o_inst)
|
||||||
|
else:
|
||||||
|
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
||||||
|
|
||||||
|
def reload_plugin(o_inst):
|
||||||
|
'''
|
||||||
|
Reloads (stops and starts) all plugins, or the given plugin
|
||||||
|
'''
|
||||||
|
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
plugin_name = sys.argv[2]
|
||||||
|
logger.info('Reloading plugin "%s"...' % plugin_name)
|
||||||
|
plugins.stop(plugin_name, o_inst)
|
||||||
|
plugins.start(plugin_name, o_inst)
|
||||||
|
else:
|
||||||
|
logger.info('Reloading all plugins...')
|
||||||
|
plugins.reload(o_inst)
|
||||||
|
|
||||||
|
|
||||||
|
def create_plugin(o_inst):
|
||||||
|
'''
|
||||||
|
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 "%s"...' % plugin_name)
|
||||||
|
|
||||||
|
os.makedirs(plugins.get_plugins_folder(plugin_name))
|
||||||
|
with open(plugins.get_plugins_folder(plugin_name) + '/main.py', 'a') as main:
|
||||||
|
contents = ''
|
||||||
|
with open('static-data/default_plugin.py', 'rb') as file:
|
||||||
|
contents = file.read().decode()
|
||||||
|
|
||||||
|
# TODO: Fix $user. os.getlogin() is B U G G Y
|
||||||
|
main.write(contents.replace('$user', 'some random developer').replace('$date', datetime.datetime.now().strftime('%Y-%m-%d')).replace('$name', plugin_name))
|
||||||
|
|
||||||
|
with open(plugins.get_plugins_folder(plugin_name) + '/info.json', 'a') as main:
|
||||||
|
main.write(json.dumps({'author' : 'anonymous', 'description' : 'the default description of the plugin', 'version' : '1.0'}))
|
||||||
|
|
||||||
|
logger.info('Enabling plugin "%s"...' % plugin_name)
|
||||||
|
plugins.enable(plugin_name, o_inst)
|
||||||
|
else:
|
||||||
|
logger.warn('Cannot create plugin directory structure; plugin "%s" exists.' % plugin_name)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Failed to create plugin directory structure.', e)
|
||||||
|
else:
|
||||||
|
logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
|
@ -17,10 +17,8 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
'''
|
'''
|
||||||
|
import multiprocessing, nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, sys, base64, json
|
||||||
import nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, logger, sys, base64, json
|
import core, onionrutils, config, logger, onionrblockapi
|
||||||
import core, onionrutils, config
|
|
||||||
import onionrblockapi
|
|
||||||
|
|
||||||
def getDifficultyModifier(coreOrUtilsInst=None):
|
def getDifficultyModifier(coreOrUtilsInst=None):
|
||||||
'''Accepts a core or utils instance returns
|
'''Accepts a core or utils instance returns
|
||||||
|
69
onionr/setupconfig.py
Normal file
69
onionr/setupconfig.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import os, json
|
||||||
|
import config, logger
|
||||||
|
|
||||||
|
def setup_config(dataDir, o_inst = None):
|
||||||
|
data_exists = os.path.exists(dataDir)
|
||||||
|
|
||||||
|
if not data_exists:
|
||||||
|
os.mkdir(dataDir)
|
||||||
|
|
||||||
|
if os.path.exists('static-data/default_config.json'):
|
||||||
|
# this is the default config, it will be overwritten if a config file already exists. Else, it saves it
|
||||||
|
with open('static-data/default_config.json', 'r') as configReadIn:
|
||||||
|
config.set_config(json.loads(configReadIn.read()))
|
||||||
|
else:
|
||||||
|
# the default config file doesn't exist, try hardcoded config
|
||||||
|
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
|
||||||
|
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
|
||||||
|
if not data_exists:
|
||||||
|
config.save()
|
||||||
|
config.reload() # this will read the configuration file into memory
|
||||||
|
|
||||||
|
settings = 0b000
|
||||||
|
if config.get('log.console.color', True):
|
||||||
|
settings = settings | logger.USE_ANSI
|
||||||
|
if config.get('log.console.output', True):
|
||||||
|
settings = settings | logger.OUTPUT_TO_CONSOLE
|
||||||
|
if config.get('log.file.output', True):
|
||||||
|
settings = settings | logger.OUTPUT_TO_FILE
|
||||||
|
logger.set_settings(settings)
|
||||||
|
|
||||||
|
if not o_inst is None:
|
||||||
|
if str(config.get('general.dev_mode', True)).lower() == 'true':
|
||||||
|
o_inst._developmentMode = True
|
||||||
|
logger.set_level(logger.LEVEL_DEBUG)
|
||||||
|
else:
|
||||||
|
o_inst._developmentMode = False
|
||||||
|
logger.set_level(logger.LEVEL_INFO)
|
||||||
|
|
||||||
|
verbosity = str(config.get('log.verbosity', 'default')).lower().strip()
|
||||||
|
if not verbosity in ['default', 'null', 'none', 'nil']:
|
||||||
|
map = {
|
||||||
|
str(logger.LEVEL_DEBUG) : logger.LEVEL_DEBUG,
|
||||||
|
'verbose' : logger.LEVEL_DEBUG,
|
||||||
|
'debug' : logger.LEVEL_DEBUG,
|
||||||
|
str(logger.LEVEL_INFO) : logger.LEVEL_INFO,
|
||||||
|
'info' : logger.LEVEL_INFO,
|
||||||
|
'information' : logger.LEVEL_INFO,
|
||||||
|
str(logger.LEVEL_WARN) : logger.LEVEL_WARN,
|
||||||
|
'warn' : logger.LEVEL_WARN,
|
||||||
|
'warning' : logger.LEVEL_WARN,
|
||||||
|
'warnings' : logger.LEVEL_WARN,
|
||||||
|
str(logger.LEVEL_ERROR) : logger.LEVEL_ERROR,
|
||||||
|
'err' : logger.LEVEL_ERROR,
|
||||||
|
'error' : logger.LEVEL_ERROR,
|
||||||
|
'errors' : logger.LEVEL_ERROR,
|
||||||
|
str(logger.LEVEL_FATAL) : logger.LEVEL_FATAL,
|
||||||
|
'fatal' : logger.LEVEL_FATAL,
|
||||||
|
str(logger.LEVEL_IMPORTANT) : logger.LEVEL_IMPORTANT,
|
||||||
|
'silent' : logger.LEVEL_IMPORTANT,
|
||||||
|
'quiet' : logger.LEVEL_IMPORTANT,
|
||||||
|
'important' : logger.LEVEL_IMPORTANT
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbosity in map:
|
||||||
|
logger.set_level(map[verbosity])
|
||||||
|
else:
|
||||||
|
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
|
||||||
|
|
||||||
|
return data_exists
|
9
requirements.in
Executable file
9
requirements.in
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
urllib3==1.23
|
||||||
|
requests==2.20.0
|
||||||
|
PyNaCl==1.2.1
|
||||||
|
gevent==1.3.6
|
||||||
|
defusedxml==0.5.0
|
||||||
|
Flask==1.0.2
|
||||||
|
PySocks==1.6.8
|
||||||
|
stem==1.6.0
|
||||||
|
deadsimplekv==0.0.1
|
205
requirements.txt
Executable file → Normal file
205
requirements.txt
Executable file → Normal file
@ -1,9 +1,196 @@
|
|||||||
urllib3==1.23
|
#
|
||||||
requests==2.20.0
|
# This file is autogenerated by pip-compile
|
||||||
PyNaCl==1.2.1
|
# To update, run:
|
||||||
gevent==1.3.6
|
#
|
||||||
defusedxml==0.5.0
|
# pip-compile --generate-hashes --output-file requirements.txt requirements.in
|
||||||
Flask==1.0.2
|
#
|
||||||
PySocks==1.6.8
|
certifi==2018.11.29 \
|
||||||
stem==1.6.0
|
--hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
|
||||||
deadsimplekv==0.0.1
|
--hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
|
||||||
|
# via requests
|
||||||
|
cffi==1.12.2 \
|
||||||
|
--hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
|
||||||
|
--hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
|
||||||
|
--hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
|
||||||
|
--hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
|
||||||
|
--hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
|
||||||
|
--hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
|
||||||
|
--hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
|
||||||
|
--hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
|
||||||
|
--hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
|
||||||
|
--hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
|
||||||
|
--hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
|
||||||
|
--hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
|
||||||
|
--hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
|
||||||
|
--hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
|
||||||
|
--hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
|
||||||
|
--hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
|
||||||
|
--hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
|
||||||
|
--hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
|
||||||
|
--hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
|
||||||
|
--hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
|
||||||
|
--hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
|
||||||
|
--hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
|
||||||
|
--hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
|
||||||
|
--hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
|
||||||
|
--hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
|
||||||
|
--hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
|
||||||
|
--hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
|
||||||
|
--hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889 \
|
||||||
|
# via pynacl
|
||||||
|
chardet==3.0.4 \
|
||||||
|
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
|
||||||
|
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 \
|
||||||
|
# via requests
|
||||||
|
click==7.0 \
|
||||||
|
--hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13 \
|
||||||
|
--hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7 \
|
||||||
|
# via flask
|
||||||
|
deadsimplekv==0.0.1 \
|
||||||
|
--hash=sha256:1bb78e4feb01d975e89e81cac7b0141666a14ebefa06fffc1c2d86c3308e3930
|
||||||
|
defusedxml==0.5.0 \
|
||||||
|
--hash=sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4 \
|
||||||
|
--hash=sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20
|
||||||
|
flask==1.0.2 \
|
||||||
|
--hash=sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48 \
|
||||||
|
--hash=sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05
|
||||||
|
gevent==1.3.6 \
|
||||||
|
--hash=sha256:03d03ea4f33e535b0a99b6be2696fde9c7417022b8ee67fb15b78f47672a0b86 \
|
||||||
|
--hash=sha256:13a0e74432ede9efdad5fd9aed73bd30bcfc73ddcbffe719849210f4546db833 \
|
||||||
|
--hash=sha256:23d623b41a431e04a9410b046520778517f5304dfbb9bfd3b1bbcc722eeaeea5 \
|
||||||
|
--hash=sha256:2f82d8b4d09285ca4aef34ae5c093ccf966da90e7db3bd34764ffb014c8bfa68 \
|
||||||
|
--hash=sha256:3223eb697d819d73dedc9a55b3dfa0cc1931e6459df4f0bf83c7c27ca256a3bd \
|
||||||
|
--hash=sha256:3c00ade4ae707dd6a17d6d56ebac689dc56719b83389f9aeb6a10b1e01326177 \
|
||||||
|
--hash=sha256:652bdd59afb330ad95550bda6864b87876e977aa4e48b9216235d932368e1987 \
|
||||||
|
--hash=sha256:7b413c391e8ad6607b7f7540d698a94349abd64e4935184c595f7cdcc69904c6 \
|
||||||
|
--hash=sha256:7feaf556fe2dc94340b603a3bfb00fbb526aaafcb8d804960939244ace4a262f \
|
||||||
|
--hash=sha256:810ae07c1baee83cb3d54f7dca236803554659dc00ef662ac962e4e4fd3e79bb \
|
||||||
|
--hash=sha256:86fa642228b8fc6a8fa268efab20440bb26599d28814e8dcd99af5dc92da10d7 \
|
||||||
|
--hash=sha256:a9a0a61f8dc652b3dd5dc8b9f5f9ace5d2f91f5e81f368e9ef180c8eec968234 \
|
||||||
|
--hash=sha256:ac3d258521b1056acb922b3aa77031a64888bb8cda1f7f6f370692cf3e224761 \
|
||||||
|
--hash=sha256:af7b0d16541dea42f1eceac4a02815ea3ebd8fe1eb6fc714c81ab1842ec259d4 \
|
||||||
|
--hash=sha256:bafef5a426473b52648c25d0ff9027aa8806982b57f8bc03abcc5f4669bfe19f \
|
||||||
|
--hash=sha256:bc31cdec2e584106c026a4fd24f800cb575ea8ebfcce7974b630b65d61cf36df \
|
||||||
|
--hash=sha256:cc42af305cb7bf1766b0084011520a81e56315dcc5b7662c209ef71a00764634 \
|
||||||
|
--hash=sha256:e01223b43b2e9d92733ab9953038c7a99b9c3cdb32dc865b9ce94f03a2199f96 \
|
||||||
|
--hash=sha256:e57f9d267b45ef9e3eb0e234307faaffa5a79cdb1477afa1befbf04de0cd8cbe \
|
||||||
|
--hash=sha256:e9e2942704f7fe75064ef0bc17ba46b097a57ec0e70eca1d790d5a3edb691628 \
|
||||||
|
--hash=sha256:f2ca6fc669def8e622b4a10809f6f6a4b6a822a1cc1175b89ad8eb34235aaa2e \
|
||||||
|
--hash=sha256:f456a6321f0955e802e305946ce7e7d672a7da313417ea4b4add6809630d3b0e \
|
||||||
|
--hash=sha256:ff8e09696a8c9100b1c88066ee44b50fbbea367ae91d830910561c902d1e7f3c
|
||||||
|
greenlet==0.4.15 \
|
||||||
|
--hash=sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0 \
|
||||||
|
--hash=sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28 \
|
||||||
|
--hash=sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8 \
|
||||||
|
--hash=sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304 \
|
||||||
|
--hash=sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0 \
|
||||||
|
--hash=sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214 \
|
||||||
|
--hash=sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043 \
|
||||||
|
--hash=sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6 \
|
||||||
|
--hash=sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625 \
|
||||||
|
--hash=sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc \
|
||||||
|
--hash=sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638 \
|
||||||
|
--hash=sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163 \
|
||||||
|
--hash=sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4 \
|
||||||
|
--hash=sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490 \
|
||||||
|
--hash=sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248 \
|
||||||
|
--hash=sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939 \
|
||||||
|
--hash=sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87 \
|
||||||
|
--hash=sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720 \
|
||||||
|
--hash=sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656 \
|
||||||
|
# via gevent
|
||||||
|
idna==2.7 \
|
||||||
|
--hash=sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e \
|
||||||
|
--hash=sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16 \
|
||||||
|
# via requests
|
||||||
|
itsdangerous==1.1.0 \
|
||||||
|
--hash=sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19 \
|
||||||
|
--hash=sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749 \
|
||||||
|
# via flask
|
||||||
|
jinja2==2.10 \
|
||||||
|
--hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd \
|
||||||
|
--hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4 \
|
||||||
|
# via flask
|
||||||
|
markupsafe==1.1.1 \
|
||||||
|
--hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \
|
||||||
|
--hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \
|
||||||
|
--hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \
|
||||||
|
--hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \
|
||||||
|
--hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \
|
||||||
|
--hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b \
|
||||||
|
--hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \
|
||||||
|
--hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \
|
||||||
|
--hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \
|
||||||
|
--hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \
|
||||||
|
--hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \
|
||||||
|
--hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \
|
||||||
|
--hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \
|
||||||
|
--hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \
|
||||||
|
--hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \
|
||||||
|
--hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \
|
||||||
|
--hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \
|
||||||
|
--hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \
|
||||||
|
--hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \
|
||||||
|
--hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \
|
||||||
|
--hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \
|
||||||
|
--hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \
|
||||||
|
--hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \
|
||||||
|
--hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \
|
||||||
|
--hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \
|
||||||
|
--hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \
|
||||||
|
--hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \
|
||||||
|
--hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \
|
||||||
|
# via jinja2
|
||||||
|
pycparser==2.19 \
|
||||||
|
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3 \
|
||||||
|
# via cffi
|
||||||
|
pynacl==1.2.1 \
|
||||||
|
--hash=sha256:04e30e5bdeeb2d5b34107f28cd2f5bbfdc6c616f3be88fc6f53582ff1669eeca \
|
||||||
|
--hash=sha256:0bfa0d94d2be6874e40f896e0a67e290749151e7de767c5aefbad1121cad7512 \
|
||||||
|
--hash=sha256:11aa4e141b2456ce5cecc19c130e970793fa3a2c2e6fbb8ad65b28f35aa9e6b6 \
|
||||||
|
--hash=sha256:13bdc1fe084ff9ac7653ae5a924cae03bf4bb07c6667c9eb5b6eb3c570220776 \
|
||||||
|
--hash=sha256:14339dc233e7a9dda80a3800e64e7ff89d0878ba23360eea24f1af1b13772cac \
|
||||||
|
--hash=sha256:1d33e775fab3f383167afb20b9927aaf4961b953d76eeb271a5703a6d756b65b \
|
||||||
|
--hash=sha256:2a42b2399d0428619e58dac7734838102d35f6dcdee149e0088823629bf99fbb \
|
||||||
|
--hash=sha256:2dce05ac8b3c37b9e2f65eab56c544885607394753e9613fd159d5e2045c2d98 \
|
||||||
|
--hash=sha256:63cfccdc6217edcaa48369191ae4dca0c390af3c74f23c619e954973035948cd \
|
||||||
|
--hash=sha256:6453b0dae593163ffc6db6f9c9c1597d35c650598e2c39c0590d1757207a1ac2 \
|
||||||
|
--hash=sha256:73a5a96fb5fbf2215beee2353a128d382dbca83f5341f0d3c750877a236569ef \
|
||||||
|
--hash=sha256:8abb4ef79161a5f58848b30ab6fb98d8c466da21fdd65558ce1d7afc02c70b5f \
|
||||||
|
--hash=sha256:8ac1167195b32a8755de06efd5b2d2fe76fc864517dab66aaf65662cc59e1988 \
|
||||||
|
--hash=sha256:8f505f42f659012794414fa57c498404e64db78f1d98dfd40e318c569f3c783b \
|
||||||
|
--hash=sha256:9c8a06556918ee8e3ab48c65574f318f5a0a4d31437fc135da7ee9d4f9080415 \
|
||||||
|
--hash=sha256:a1e25fc5650cf64f01c9e435033e53a4aca9de30eb9929d099f3bb078e18f8f2 \
|
||||||
|
--hash=sha256:be71cd5fce04061e1f3d39597f93619c80cdd3558a6c9ba99a546f144a8d8101 \
|
||||||
|
--hash=sha256:c5b1a7a680218dee9da0f1b5e24072c46b3c275d35712bc1d505b85bb03441c0 \
|
||||||
|
--hash=sha256:cb785db1a9468841a1265c9215c60fe5d7af2fb1b209e3316a152704607fc582 \
|
||||||
|
--hash=sha256:cf6877124ae6a0698404e169b3ba534542cfbc43f939d46b927d956daf0a373a \
|
||||||
|
--hash=sha256:d0eb5b2795b7ee2cbcfcadacbe95a13afbda048a262bd369da9904fecb568975 \
|
||||||
|
--hash=sha256:d3a934e2b9f20abac009d5b6951067cfb5486889cb913192b4d8288b216842f1 \
|
||||||
|
--hash=sha256:d795f506bcc9463efb5ebb0f65ed77921dcc9e0a50499dedd89f208445de9ecb \
|
||||||
|
--hash=sha256:d8aaf7e5d6b0e0ef7d6dbf7abeb75085713d0100b4eb1a4e4e857de76d77ac45 \
|
||||||
|
--hash=sha256:de2aaca8386cf4d70f1796352f2346f48ddb0bed61dc43a3ce773ba12e064031 \
|
||||||
|
--hash=sha256:e0d38fa0a75f65f556fb912f2c6790d1fa29b7dd27a1d9cc5591b281321eaaa9 \
|
||||||
|
--hash=sha256:eb2acabbd487a46b38540a819ef67e477a674481f84a82a7ba2234b9ba46f752 \
|
||||||
|
--hash=sha256:eeee629828d0eb4f6d98ac41e9a3a6461d114d1d0aa111a8931c049359298da0 \
|
||||||
|
--hash=sha256:f5836463a3c0cca300295b229b6c7003c415a9d11f8f9288ddbd728e2746524c \
|
||||||
|
--hash=sha256:f5ce9e26d25eb0b2d96f3ef0ad70e1d3ae89b5d60255c462252a3e456a48c053 \
|
||||||
|
--hash=sha256:fabf73d5d0286f9e078774f3435601d2735c94ce9e514ac4fb945701edead7e4
|
||||||
|
pysocks==1.6.8 \
|
||||||
|
--hash=sha256:3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672
|
||||||
|
requests==2.20.0 \
|
||||||
|
--hash=sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c \
|
||||||
|
--hash=sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279
|
||||||
|
six==1.12.0 \
|
||||||
|
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
|
||||||
|
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
|
||||||
|
# via pynacl
|
||||||
|
stem==1.6.0 \
|
||||||
|
--hash=sha256:d7fe1fb13ed5a94d610b5ad77e9f1b3404db0ca0586ded7a34afd323e3b849ed
|
||||||
|
urllib3==1.23 \
|
||||||
|
--hash=sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf \
|
||||||
|
--hash=sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5
|
||||||
|
werkzeug==0.14.1 \
|
||||||
|
--hash=sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c \
|
||||||
|
--hash=sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b \
|
||||||
|
# via flask
|
||||||
|
Loading…
Reference in New Issue
Block a user