Refactor configuration management code

This commit is contained in:
Arinerron 2018-02-22 17:58:36 -08:00
parent b65c6305c5
commit 1a1317a7b6
No known key found for this signature in database
GPG Key ID: 99383627861C62F0
5 changed files with 148 additions and 32 deletions

View File

@ -20,7 +20,7 @@
import flask
from flask import request, Response, abort
from multiprocessing import Process
import configparser, sys, random, threading, hmac, hashlib, base64, time, math, os, logger
import sys, random, threading, hmac, hashlib, base64, time, math, os, logger, config
from core import Core
import onionrutils, onionrcrypto
@ -37,31 +37,32 @@ class API:
else:
return True
def __init__(self, config, debug):
def __init__(self, debug):
'''
Initialize the api server, preping variables for later use
This initilization defines all of the API entry points and handlers for the endpoints and errors
This also saves the used host (random localhost IP address) to the data folder in host.txt
'''
if os.path.exists('dev-enabled'):
config.reload()
if config.get('devmode', True):
self._developmentMode = True
logger.set_level(logger.LEVEL_DEBUG)
#logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)')
else:
self._developmentMode = False
logger.set_level(logger.LEVEL_INFO)
self.config = config
self.debug = debug
self._privateDelayTime = 3
self._core = Core()
self._crypto = onionrcrypto.OnionrCrypto(self._core)
self._utils = onionrutils.OnionrUtils(self._core)
app = flask.Flask(__name__)
bindPort = int(self.config['CLIENT']['PORT'])
bindPort = int(config.get('CLIENT')['PORT'])
self.bindPort = bindPort
self.clientToken = self.config['CLIENT']['CLIENT HMAC']
self.clientToken = config.get('CLIENT')['CLIENT HMAC']
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
logger.debug('Your HMAC token: ' + logger.colors.underline + self.clientToken)

107
onionr/config.py Normal file
View File

@ -0,0 +1,107 @@
'''
Onionr - P2P Microblogging Platform & Social network
This file deals with configuration management.
'''
'''
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
import os, json, logger
_configfile = os.path.abspath('data/config.json')
_config = {}
def get(key, default = None):
'''
Gets the key from configuration, or returns `default`
'''
if key in get_config():
return get_config()[key]
return default
def set(key, value = None, savefile = False):
'''
Sets the key in configuration to `value`
'''
global _config
_config[key] = value
if savefile:
save()
def check():
'''
Checks if the configuration file exists, creates it if not
'''
try:
if not os.path.exists(os.path.dirname(get_config_file())):
os.path.mkdirs(os.path.dirname(get_config_file()))
if not os.path.isfile(get_config_file()):
open(get_config_file(), 'a', encoding="utf8").close()
save()
except:
logger.warn('Failed to check configuration file.')
def save():
'''
Saves the configuration data to the configuration file
'''
check()
try:
with open(get_config_file(), 'w', encoding="utf8") as configfile:
json.dump(get_config(), configfile)
except:
logger.warn('Failed to write to configuration file.')
def reload():
'''
Reloads the configuration data in memory from the file
'''
check()
try:
with open(get_config_file(), 'r', encoding="utf8") as configfile:
set_config(json.loads(configfile.read()))
except:
logger.warn('Failed to parse configuration file.')
def get_config():
'''
Gets the entire configuration as an array
'''
return _config
def set_config(config):
'''
Sets the configuration to the array in arguments
'''
global _config
_config = config
def get_config_file():
'''
Returns the absolute path to the configuration file
'''
return _configfile
def set_config_file(configfile):
'''
Sets the path to the configuration file
'''
global _configfile
_configfile = os.abs.abspath(configfile)

View File

@ -20,8 +20,8 @@
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, configparser, base64, random, getpass, shutil, subprocess, requests, time, logger, platform
import api, core, gui
import sys, os, base64, random, getpass, shutil, subprocess, requests, time, platform
import api, core, gui, config, logger
from onionrutils import OnionrUtils
from netcontroller import NetController
@ -39,12 +39,19 @@ class Onionr:
Main Onionr class. This is for the CLI program, and does not handle much of the logic.
In general, external programs and plugins should not use this class.
'''
try:
os.chdir(sys.path[0])
except FileNotFoundError:
pass
if os.path.exists('dev-enabled'):
# Load global configuration data
exists = os.path.exists(config.get_config_file())
config.set_config({'devmode': True}) # this is the default config, it will be overwritten if a config file already exists. Else, it saves it
config.reload() # this will read the configuration file into memory
if config.get('devmode', True):
self._developmentMode = True
logger.set_level(logger.LEVEL_DEBUG)
else:
@ -54,7 +61,7 @@ class Onionr:
self.onionrCore = core.Core()
self.onionrUtils = OnionrUtils(self.onionrCore)
# Get configuration and Handle commands
# Handle commands
self.debug = False # Whole application debugging
@ -79,10 +86,8 @@ class Onionr:
self.onionrCore.createAddressDB()
# Get configuration
self.config = configparser.ConfigParser()
if os.path.exists('data/config.ini'):
self.config.read('data/config.ini')
else:
if not exists:
# Generate default config
# Hostname should only be set if different from 127.x.x.x. Important for DNS rebinding attack prevention.
if self.debug:
@ -92,9 +97,7 @@ class Onionr:
randomPort = random.randint(1024, 65535)
if self.onionrUtils.checkPort(randomPort):
break
self.config['CLIENT'] = {'participate': 'true', 'CLIENT HMAC': base64.b64encode(os.urandom(32)).decode('utf-8'), 'PORT': randomPort, 'API VERSION': API_VERSION}
with open('data/config.ini', 'w') as configfile:
self.config.write(configfile)
config.set('CLIENT', {'participate': 'true', 'CLIENT HMAC': base64.b64encode(os.urandom(32)).decode('utf-8'), 'PORT': randomPort, 'API VERSION': API_VERSION}, True)
command = ''
try:
@ -271,7 +274,7 @@ class Onionr:
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
if self._developmentMode:
logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)')
net = NetController(self.config['CLIENT']['PORT'])
net = NetController(config.get('CLIENT')['PORT'])
logger.info('Tor is starting...')
if not net.startTor():
sys.exit(1)
@ -280,7 +283,7 @@ class Onionr:
time.sleep(1)
subprocess.Popen(["./communicator.py", "run", str(net.socksPort)])
logger.debug('Started communicator')
api.API(self.config, self.debug)
api.API(self.debug)
return
@ -290,7 +293,7 @@ class Onionr:
'''
logger.warn('Killing the running daemon')
net = NetController(self.config['CLIENT']['PORT'])
net = NetController(config.get('CLIENT')['PORT'])
try:
self.onionrUtils.localCommand('shutdown')
except requests.exceptions.ConnectionError:

View File

@ -18,30 +18,34 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
# Misc functions that do not fit in the main api, but are useful
import getpass, sys, requests, configparser, os, socket, hashlib, logger, sqlite3
import getpass, sys, requests, os, socket, hashlib, logger, sqlite3, config
import nacl.signing, nacl.encoding
if sys.version_info < (3, 6):
try:
import sha3
except ModuleNotFoundError:
logger.fatal('On Python 3 versions prior to 3.6.x, you need the sha3 module')
sys.exit(1)
class OnionrUtils:
'''Various useful functions'''
'''
Various useful function
'''
def __init__(self, coreInstance):
self.fingerprintFile = 'data/own-fingerprint.txt'
self._core = coreInstance
return
def localCommand(self, command):
'''
Send a command to the local http API server, securely. Intended for local clients, DO NOT USE for remote peers.
'''
config = configparser.ConfigParser()
if os.path.exists('data/config.ini'):
config.read('data/config.ini')
else:
return
requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config['CLIENT']['PORT']) + '/client/?action=' + command + '&token=' + config['CLIENT']['CLIENT HMAC'])
config.reload()
# TODO: URL encode parameters, just as an extra measure. May not be needed, but should be added regardless.
requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config.get('CLIENT')['PORT']) + '/client/?action=' + command + '&token=' + config.get('CLIENT')['CLIENT HMAC'])
return
@ -141,7 +145,7 @@ class OnionrUtils:
retVal = False
return retVal
def validatePubKey(self, key):
'''Validate if a string is a valid base32 encoded Ed25519 key'''
retVal = False
@ -195,5 +199,5 @@ class OnionrUtils:
retVal = False
if not idNoDomain.isalnum():
retVal = False
return retVal
return retVal

View File

@ -5,3 +5,4 @@ simple_crypt==4.1.7
urllib3==1.19.1
sha3==0.2.1
PySocks==1.6.8
urllib3