예제 #1
0
def detect_disk_access(info):
    if type(info[0]) is int: return

    if '/dev/null' == info[0]: return

    whitelist = [
        identify_home(), 'onionr/src/', '/site-packages/', '/usr/lib64/'
    ]

    for item in whitelist:
        if item in info[0]:
            return

    if identify_home() not in info[0]:
        if 'proc' not in info[0]:  # if it is, it is onionr stats
            logger.warn(f'[DISK MINISTRY] {info}')
예제 #2
0
    def get_stats(self):
        """Return statistics about our node"""
        stats = {}
        proc = Process()

        def get_open_files():
            if WINDOWS: return proc.num_handles()
            return proc.num_fds()

        try:
            self._too_many
        except AttributeError:
            sleep(1)
        comm_inst = self._too_many.get(communicator.OnionrCommunicatorDaemon,
                                       args=(self._too_many, ))
        connected = []
        [
            connected.append(x) for x in comm_inst.onlinePeers
            if x not in connected
        ]
        stats['uptime'] = comm_inst.getUptime()
        stats['connectedNodes'] = '\n'.join(connected)
        stats['blockCount'] = len(blockmetadb.get_block_list())
        stats['blockQueueCount'] = len(comm_inst.blockQueue)
        stats['threads'] = proc.num_threads()
        stats['ramPercent'] = proc.memory_percent()
        stats['fd'] = get_open_files()
        stats['diskUsage'] = human_size(size(identify_home()))
        return json.dumps(stats)
예제 #3
0
파일: main.py 프로젝트: x0rzkov/onionr
def on_processblocks(api, data=None):
    metadata = data['block'].bmetadata # Get the block metadata
    if data['type'] != 'brd':
        return

    b_hash = reconstructhash.deconstruct_hash(data['block'].hash) # Get the 0-truncated block hash
    board_cache = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/board-index.cache.json', flush_on_exit=False) # get the board index cache
    board_cache.refresh()
    # Validate the channel name is sane for caching
    try:
        ch = metadata['ch']
    except KeyError:
        ch = 'global'
    ch_len = len(ch)
    if ch_len == 0:
        ch = 'global'
    elif ch_len > 12:
        return
    
    existing_posts = board_cache.get(ch)
    if existing_posts is None:
        existing_posts = []
    existing_posts.append(data['block'].hash)
    board_cache.put(ch, existing_posts)
    board_cache.flush()
예제 #4
0
 def test_torrc_get(self):
     torrc = identifyhome.identify_home() + '/torrc-custom'
     self.assertEqual(customtorrc.get_custom_torrc(), '\n')
     with open(torrc, 'w') as torrc_file:
         torrc_file.write('test')
     self.assertEqual(customtorrc.get_custom_torrc(), '\ntest')
     os.remove(torrc)
예제 #5
0
def block_exec(event, info):
    """Prevent arbitrary code execution in eval/exec and log it."""
    # because libraries have stupid amounts of compile/exec/eval,
    # We have to use a whitelist where it can be tolerated
    # Generally better than nothing, not a silver bullet
    whitelisted_code = [
        'netrc.py', 'shlex.py', 'gzip.py', '<werkzeug routing>',
        'werkzeug/test.py', 'multiprocessing/popen_fork.py',
        'multiprocessing/util.py', 'multiprocessing/connection.py',
        'multiprocessing/queues.py', 'multiprocessing/synchronize.py',
        'onionrutils/escapeansi.py', 'stem/connection.py',
        'stem/response/add_onion.py', 'stem/response/authchallenge.py',
        'stem/response/getinfo.py', 'stem/response/getconf.py',
        'stem/response/mapaddress.py', 'stem/response/protocolinfo.py',
        'apport/__init__.py', 'apport/report.py'
    ]
    whitelisted_source = []
    home = identifyhome.identify_home()

    code_b64 = base64.b64encode(info[0].co_code).decode()
    if code_b64 in whitelisted_source:
        return

    for source in whitelisted_code:
        if info[0].co_filename.endswith(source):
            return

    if 'plugins/' in info[0].co_filename:
        return

    logger.warn('POSSIBLE EXPLOIT DETECTED, SEE LOGS', terminal=True)
    logger.warn('POSSIBLE EXPLOIT DETECTED: ' + info[0].co_filename)
    logger.warn('Prevented exec/eval. Report this with the sample below')
    logger.warn(f'{event} code in base64 format: {code_b64}')
    raise ArbitraryCodeExec("Arbitrary code (eval/exec) detected.")
예제 #6
0
    def get_stats(self):
        """Return statistics about our node"""
        stats = {}
        proc = Process()

        def get_open_files():
            if WINDOWS:
                return proc.num_handles()
            return proc.num_fds()

        try:
            self._too_many
        except AttributeError:
            sleep(1)
        kv: "DeadSimpleKV" = self._too_many.get_by_string("DeadSimpleKV")
        connected = []
        [
            connected.append(x) for x in kv.get('onlinePeers')
            if x not in connected
        ]
        stats['uptime'] = get_epoch() - kv.get('startTime')
        stats['connectedNodes'] = '\n'.join(connected)
        stats['blockCount'] = len(blockmetadb.get_block_list())
        stats['blockQueueCount'] = len(kv.get('blockQueue'))
        stats['threads'] = proc.num_threads()
        stats['ramPercent'] = proc.memory_percent()
        stats['fd'] = get_open_files()
        stats['diskUsage'] = human_size(size(identify_home()))
        return json.dumps(stats)
예제 #7
0
def reset():
    """Reinstalls Onionr default plugins"""
    home = identifyhome.identify_home()
    plugin_dir = home + '/plugins/'
    if not os.path.exists(home): return
    if os.path.exists(plugin_dir): shutil.rmtree(plugin_dir)

    logger.info('Default plugins have been reset.', terminal=True)
예제 #8
0
 def auto_refresher():
     observer = Observer()
     observer.schedule(Refresher(),
                       identify_home(),
                       recursive=False)
     observer.start()
     while observer.is_alive():
         # call import func with timeout
         observer.join(120)
예제 #9
0
파일: flowapi.py 프로젝트: x0rzkov/onionr
def get_post_by_board(board):
    board_cache = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/board-index.cache.json', flush_on_exit=False)
    board_cache.refresh()
    posts = board_cache.get(board)
    if posts is None:
        posts = ''
    else:
        posts = ','.join(posts)
    return Response(posts)
예제 #10
0
파일: resettor.py 프로젝트: x0rzkov/onionr
def __delete(directory):
    tor_dir = '%s/%s/' % (identifyhome.identify_home(), directory)
    if os.path.exists(tor_dir):
        if localcommand.local_command('/ping') == 'pong!':
            logger.warn('Cannot delete Tor data while Onionr is running',
                        terminal=True)
        else:
            shutil.rmtree(tor_dir)
            logger.info('Tor reset', terminal=True)
예제 #11
0
def generate_torrc(net_controller: 'NetController',
                   api_server_ip: 'LoopBackIP'):
    """Generate a torrc file for our tor instance."""
    socks_port = net_controller.socksPort
    hs_port = net_controller.hsPort
    home_dir = identifyhome.identify_home()
    tor_config_location = home_dir + '/torrc'

    hs_ver = 'HiddenServiceVersion 3'

    """
    Set the Tor control password.
    Meant to make it harder to manipulate our Tor instance
    """
    plaintext = base64.b85encode(
        os.urandom(50)).decode()
    config.set('tor.controlpassword', plaintext, savefile=True)
    config.set('tor.socksport', socks_port, savefile=True)

    control_port = getopenport.get_open_port()

    config.set('tor.controlPort', control_port, savefile=True)

    hashedPassword = subprocess.Popen([torbinary.tor_binary(),
                                      '--hash-password',
                                       plaintext],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)
    for line in iter(hashedPassword.stdout.readline, b''):
        password = line.decode()
        if 'warn' not in password:
            break

    torrc_data = """SocksPort """ + str(socks_port) + """ OnionTrafficOnly
DataDirectory """ + home_dir + """tordata/
CookieAuthentication 1
KeepalivePeriod 40
CircuitsAvailableTimeout 86400
ControlPort """ + str(control_port) + """
HashedControlPassword """ + str(password) + """
    """
    if config.get('general.security_level', 1) == 0:
        torrc_data += """\nHiddenServiceDir """ + home_dir + """hs/
\n""" + hs_ver + """\n
HiddenServiceNumIntroductionPoints 20
HiddenServiceMaxStreams 500
HiddenServiceMaxStreamsCloseCircuit 1
HiddenServicePort 80 """ + api_server_ip + """:""" + str(hs_port)

    torrc_data = add_bridges(torrc_data)

    torrc_data += customtorrc.get_custom_torrc()

    torrc = open(tor_config_location, 'w')
    torrc.write(torrc_data)
    torrc.close()
예제 #12
0
 def __init__(self, hsPort, apiServerIP='127.0.0.1'):
     # set data dir
     self.dataDir = identifyhome.identify_home()
     self.socksPort = getopenport.get_open_port()
     self.torConfigLocation = self.dataDir + 'torrc'
     self.readyState = False
     self.hsPort = hsPort
     self._torInstnace = ''
     self.myID = ''
     self.apiServerIP = apiServerIP
     self.torBinary = torbinary.tor_binary()
예제 #13
0
파일: flowapi.py 프로젝트: x0rzkov/onionr
def get_post_by_board_with_offset(board, offset):
    offset = int(offset)
    OFFSET_COUNT = 10
    board_cache = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/board-index.cache.json', flush_on_exit=False)
    board_cache.refresh()
    posts = board_cache.get(board)
    if posts is None:
        posts = ''
    else:
        posts.reverse()
        posts = ','.join(posts[offset:offset + OFFSET_COUNT])
    return Response(posts)
예제 #14
0
    def test_contact_get_info(self):
        contact = crypto.generate()[0]
        contact = contactmanager.ContactManager(contact, saveUser=True)
        fileLocation = '%s/contacts/%s.json' % (identifyhome.identify_home(),
                                                contact.publicKey)

        with open(fileLocation, 'w') as contactFile:
            contactFile.write('{"alias": "bob"}')

        self.assertEqual(contact.get_info('alias', forceReload=True), 'bob')
        self.assertEqual(contact.get_info('fail', forceReload=True), None)
        self.assertEqual(contact.get_info('fail'), None)
예제 #15
0
    def test_contact_set_info(self):
        contact = crypto.generate()[0]
        contact = contactmanager.ContactManager(contact, saveUser=True)
        fileLocation = '%s/contacts/%s.json' % (identifyhome.identify_home(),
                                                contact.publicKey)
        contact.set_info('alias', 'bob')
        self.assertTrue(os.path.exists(fileLocation))

        with open(fileLocation, 'r') as data:
            data = data.read()

        data = json.loads(data)
        self.assertEqual(data['alias'], 'bob')
예제 #16
0
def load_inbox():
    inbox_list = []
    deleted = simplekv.DeadSimpleKV(identifyhome.identify_home() +
                                    '/mailcache.dat').get('deleted_mail')
    if deleted is None:
        deleted = []

    for blockHash in blockmetadb.get_blocks_by_type('pm'):
        block = onionrblockapi.Block(blockHash)
        block.decrypt()
        if block.decrypted and reconstructhash.deconstruct_hash(
                blockHash) not in deleted:
            inbox_list.append(blockHash)
    return inbox_list
예제 #17
0
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:
        pf = platform.platform()
        release = platform.release()
        python_imp = platform.python_implementation()
        python_version = platform.python_version()
        function(f'{python_imp} {python_version} on {pf} {release}', terminal=True)
        function('Onionr data dir: %s' % identifyhome.identify_home(), terminal=True)
예제 #18
0
    def __init__(self, hsPort, apiServerIP='127.0.0.1'):
        # set data dir
        self.dataDir = identifyhome.identify_home()

        self.torConfigLocation = self.dataDir + 'torrc'
        self.readyState = False
        self.socksPort = getopenport.get_open_port()
        self.hsPort = hsPort
        self._torInstnace = ''
        self.myID = ''
        self.apiServerIP = apiServerIP

        if os.path.exists('./tor'):
            self.torBinary = './tor'
        elif os.path.exists('/usr/bin/tor'):
            self.torBinary = '/usr/bin/tor'
        else:
            self.torBinary = 'tor'
예제 #19
0
파일: __init__.py 프로젝트: infoabcd/inti
def offset_reader_endpoint(name):
    if not name[:-4].isalnum():
        return Response(400, "Path must be alphanumeric except for file ext")

    path = identify_home() + name

    if not exists(path):
        return Response(404, "Path not found in Onionr data directory")

    offset = request.args.get('offset')

    if not offset:
        offset = 0
    else:
        offset = int(offset)
    result = read_from_offset(path, offset)._asdict()

    return ujson.dumps(result, reject_bytes=False)
예제 #20
0
def show_details():
    """Print out details.

    node transport address(es)
    active user ID
        active user ID in mnemonic form
    """
    details = {
        'Data directory': identifyhome.identify_home(),
        'Node Address': gethostname.get_hostname(),
        'Public Key': onionrcrypto.pub_key.replace('=', ''),
        'Human-readable Public Key': mnemonickeys.get_human_readable_ID()
    }

    for detail in details:
        logger.info('%s%s: \n%s%s\n' %
                    (logger.colors.fg.lightgreen, detail,
                     logger.colors.fg.green, details[detail]),
                    terminal=True)
예제 #21
0
    def __init__(self, publicKey, saveUser=False, recordExpireSeconds=5):
        try:
            if mnemonickeys.DELIMITER in publicKey:
                publicKey = mnemonickeys.get_base32(publicKey)
                #publicKey = unpaddedbase32.b32encode(bytesconverter.str_to_bytes(publicKey))
        except ValueError:
            pass
        publicKey = bytesconverter.bytes_to_str(
            unpaddedbase32.repad(bytesconverter.str_to_bytes(publicKey)))
        super(ContactManager, self).__init__(publicKey, saveUser=saveUser)
        home = identifyhome.identify_home()
        self.dataDir = home + '/contacts/'
        self.dataFile = '%s/contacts/%s.json' % (home, publicKey)
        self.lastRead = 0
        self.recordExpire = recordExpireSeconds
        self.data = self._loadData()
        self.deleted = False

        if not os.path.exists(self.dataDir):
            os.mkdir(self.dataDir)
예제 #22
0
 def test_delete_contact(self):
     contact = crypto.generate()[0]
     contact = contactmanager.ContactManager(contact, saveUser=True)
     fileLocation = '%s/contacts/%s.json' % (identifyhome.identify_home(),
                                             contact.publicKey)
     self.assertFalse(os.path.exists(fileLocation))
     with open(fileLocation, 'w') as contactFile:
         contactFile.write('{"alias": "test"}')
     self.assertTrue(os.path.exists(fileLocation))
     contact.delete_contact()
     self.assertFalse(os.path.exists(fileLocation))
     try:
         contact.get_info('alias')
     except onionrexceptions.ContactDeleted:
         pass
     else:
         self.assertTrue(False)
     try:
         contact.set_info('alias', 'test2')
     except onionrexceptions.ContactDeleted:
         pass
     else:
         self.assertTrue(False)
예제 #23
0
파일: __init__.py 프로젝트: x0rzkov/onionr
    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 os, re, importlib

from . import onionrevents as events
import config, logger
from utils import identifyhome

# set data dir
dataDir = identifyhome.identify_home()

_pluginsfolder = dataDir + 'plugins/'
_instances = dict()
config.reload()


def reload(stop_event=True):
    '''
        Reloads all the plugins
    '''

    check()

    try:
        enabled_plugins = get_enabled_plugins()
예제 #24
0
파일: main.py 프로젝트: x0rzkov/onionr
def on_softreset(api, data=None):
    try:
        os.remove(identifyhome.identify_home() + '/board-index.cache.json')
        logger.info('Cleared Circles board cache')
    except FileNotFoundError:
        pass
예제 #25
0
파일: settings.py 프로젝트: x0rzkov/onionr
    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 os
from utils import identifyhome

data_home = os.environ.get('ONIONR_LOG_DIR', identifyhome.identify_home())
# Use the bitwise operators to merge these settings
USE_ANSI = 0b100
if os.name == 'nt':
    USE_ANSI = 0b000
OUTPUT_TO_CONSOLE = 0b010
OUTPUT_TO_FILE = 0b001

LEVEL_DEBUG = 1
LEVEL_INFO = 2
LEVEL_WARN = 3
LEVEL_ERROR = 4
LEVEL_FATAL = 5
LEVEL_IMPORTANT = 6

MAX_LOG_FILE_LINES = 10000
예제 #26
0
파일: flowapi.py 프로젝트: infoabcd/inti
    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/>.
"""

flask_blueprint = Blueprint('circles', __name__)

root = os.path.dirname(os.path.realpath(__file__))

with open(os.path.dirname(os.path.realpath(__file__)) + '/info.json',
          'r') as info_file:
    data = info_file.read().strip()
    version = json.loads(data)['version']

BOARD_CACHE_FILE = identifyhome.identify_home() + '/board-index.cache.json'

read_only_cache = DeadSimpleKV(BOARD_CACHE_FILE,
                               flush_on_exit=False,
                               refresh_seconds=30)


@flask_blueprint.route('/board/<path:path>', endpoint='circlesstatic')
def load_mail(path):
    return send_from_directory(root + '/web/', path)


@flask_blueprint.route('/board/', endpoint='circlesindex')
def load_mail_index():
    return send_from_directory(root + '/web/', 'index.html')
예제 #27
0
    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, os, json
from flask import Response, request, redirect, Blueprint, abort
from onionrusers import contactmanager
from onionrutils import stringvalidators
from utils import reconstructhash, identifyhome
import filepaths
import deadsimplekv as simplekv
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
import loadinbox, sentboxdb

flask_blueprint = Blueprint('mail', __name__)
kv = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/mailcache.dat')


@flask_blueprint.route('/mail/ping')
def mail_ping():
    return 'pong!'


@flask_blueprint.route('/mail/deletemsg/<block>', methods=['POST'])
def mail_delete(block):
    if not stringvalidators.validate_hash(block):
        abort(504)
    block = reconstructhash.deconstruct_hash(block)
    existing = kv.get('deleted_mail')
    if existing is None:
        existing = []
예제 #28
0
def daemon():
    """Start Onionr's primary threads for communicator, API server, node, and LAN."""

    def _handle_sig_term(signum, frame):
        pid = str(os.getpid())
        main_pid = localcommand.local_command('/getpid')
        #logger.info(main_pid, terminal=True)
        if main_pid and main_pid == pid:
            logger.info(
            f"Received sigterm, shutting down gracefully. PID: {pid}", terminal=True)
            localcommand.local_command('/shutdownclean')
        else:
            logger.info(
                f"Recieved sigterm in child process or fork, exiting. PID: {pid}")
            sys.exit(0)
    signal.signal(signal.SIGTERM, _handle_sig_term)

    # Determine if Onionr is in offline mode.
    # When offline, Onionr can only use LAN and disk transport
    offline_mode = config.get('general.offline_mode', False)

    if not hastor.has_tor():
        offline_mode = True
        logger.error("Tor is not present in system path or Onionr directory",
                     terminal=True)

    # Create shared objects

    shared_state = toomanyobjs.TooMany()

    # Add DeadSimpleKV for quasi-global variables (ephemeral key-value)
    shared_state.get(DeadSimpleKV)

    # Initialize the quasi-global variables
    setup_kv(shared_state.get(DeadSimpleKV))

    shared_state.get(daemoneventsapi.DaemonEventsBP)

    Thread(target=shared_state.get(apiservers.ClientAPI).start,
           daemon=True, name='client HTTP API').start()
    if not offline_mode:
        Thread(target=shared_state.get(apiservers.PublicAPI).start,
               daemon=True, name='public HTTP API').start()

    # Init run time tester
    # (ensures Onionr is running right, for testing purposes)
    # Run time tests are not normally run
    shared_state.get(runtests.OnionrRunTestManager)

    # Create singleton
    shared_state.get(serializeddata.SerializedData)

    shared_state.share_object()  # share the parent object to the threads

    show_logo()

    # since we randomize loopback API server hostname to protect against attacks,
    # we have to wait for it to become set
    apiHost = ''
    if not offline_mode:
        apiHost = get_api_host_until_available()

    net = NetController(config.get('client.public.port', 59497),
                        apiServerIP=apiHost)
    shared_state.add(net)

    shared_state.get(onionrstatistics.tor.TorStats)

    security_level = config.get('general.security_level', 1)
    use_existing_tor = config.get('tor.use_existing_tor', False)

    if not offline_mode:
        # we need to setup tor for use
        _setup_online_mode(use_existing_tor, net, security_level)

    _show_info_messages()
    logger.info(
        "Onionr daemon is running under " + str(os.getpid()), terminal=True)
    events.event('init', threaded=False)
    events.event('daemon_start')
    if config.get('transports.lan', True):
        if not onionrvalues.IS_QUBES:
            Thread(target=LANServer(shared_state).start_server,
                   daemon=True).start()
            LANManager(shared_state).start()
        else:
            logger.warn('LAN not supported on Qubes', terminal=True)
    if config.get('transports.sneakernet', True):
        Thread(target=sneakernet_import_thread, daemon=True).start()

    Thread(target=statistics_reporter,
           args=[shared_state], daemon=True).start()

    shared_state.get(DeadSimpleKV).put(
        'proxyPort', net.socksPort)
    spawn_client_threads(shared_state)

    clean_blocks_not_meeting_pow(shared_state)

    communicator.startCommunicator(shared_state)

    clean_ephemeral_services()

    if not offline_mode and not use_existing_tor:
        net.killTor()
    else:
        try:
            os.remove(filepaths.tor_hs_address_file)
        except FileNotFoundError:
            pass

    better_sleep(5)

    cleanup.delete_run_files()
    if security_level >= 2:
        filenuke.nuke.clean_tree(identifyhome.identify_home())
예제 #29
0
    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/>.
"""
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
direct_blueprint = Blueprint('chat', __name__)

key_store = simplekv.DeadSimpleKV(filepaths.cached_storage, refresh_seconds=5)
storage_dir = identifyhome.identify_home()


@direct_blueprint.before_request
def request_setup():
    key_store.refresh()
    host = request.host
    host = host.strip('.b32.i2p')
    host = host.strip('.onion')
    g.host = host
    g.peer = key_store.get('dc-' + g.host)


@direct_blueprint.route('/chat/ping')
def pingdirect():
    return 'pong!'
예제 #30
0
파일: __init__.py 프로젝트: threeape/onionr
from utils import identifyhome
import os
home = identifyhome.identify_home()
if not home.endswith('/'): home += '/'

app_root = os.path.dirname(os.path.realpath(__file__)) + '/../../'
usage_file = home + 'disk-usage.txt'
block_data_location = home + 'blocks/'
contacts_location = home + 'contacts/'
public_API_host_file = home + 'public-host.txt'
private_API_host_file = home + 'private-host.txt'
bootstrap_file_location = 'static-data/bootstrap-nodes.txt'
data_nonce_file = home + 'block-nonces.dat'
forward_keys_file = home + 'forward-keys.db'
cached_storage = home + 'cachedstorage.dat'
announce_cache = home + 'announcecache.dat'
export_location = home + 'block-export/'
upload_list = home + 'upload-list.json'
config_file = home + 'config.json'
daemon_mark_file = home + '/daemon-true.txt'
lock_file = home + 'onionr.lock'

site_cache = home + 'onionr-sites.txt'

tor_hs_loc = home + 'hs/'
tor_hs_address_file = home + 'hs/hostname'

run_check_file = home + '.runcheck'

data_nonce_file = home + 'block-nonces.dat'