Refactor configuration management code
parent
b65c6305c5
commit
1a1317a7b6
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,3 +5,4 @@ simple_crypt==4.1.7
|
|||
urllib3==1.19.1
|
||||
sha3==0.2.1
|
||||
PySocks==1.6.8
|
||||
urllib3
|
||||
|
|
Loading…
Reference in New Issue