added config observers, delete plaintext blocks when plaintext storage is disabled

This commit is contained in:
Kevin Froman 2020-01-07 05:44:53 -06:00
parent 2e31155a5d
commit f78809fa2a
9 changed files with 156 additions and 116 deletions

View File

@ -1,9 +1,12 @@
'''
Onionr - Private P2P Communication
"""Onionr - Private P2P Communication.
This file deals with configuration management.
'''
'''
This file deals with configuration management.
"""
import os, json, logger
import filepaths
from . import onboarding
"""
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
@ -16,20 +19,14 @@
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
import filepaths
from . import onboarding
"""
_configfile = filepaths.config_file
_config = {}
def get(key, default = None, save = False):
'''
Gets the key from configuration, or returns `default`
'''
"""Gets the key from configuration, or returns `default`"""
key = str(key).split('.')
data = _config
@ -41,20 +38,24 @@ def get(key, default = None, save = False):
return default
data = data[item]
if not last in data:
if last not in data:
if save:
set(key, default, savefile = True)
return default
return data[last]
def set(key, value = None, savefile = False):
'''
Sets the key in configuration to `value`
'''
"""Sets the key in configuration to `value`"""
from . import observers
config_set_observers = {
'general.store_plaintext_blocks': [observers.delete_plaintext]
}
global _config
whole_key = key
key = str(key).split('.')
data = _config
@ -64,6 +65,11 @@ def set(key, value = None, savefile = False):
if (not item in data) or (not type(data[item]) == dict):
data[item] = dict()
data = data[item]
try:
for observer in config_set_observers[whole_key]:
observer(value)
except KeyError:
pass
if value is None:
del data[last]
@ -73,6 +79,7 @@ def set(key, value = None, savefile = False):
if savefile:
save()
def is_set(key):
key = str(key).split('.')
data = _config
@ -89,18 +96,16 @@ def is_set(key):
return True
def check():
'''
Checks if the configuration file exists, creates it if not
'''
"""Checks if the configuration file exists, creates it if not"""
if not os.path.exists(os.path.dirname(get_config_file())):
os.makedirs(os.path.dirname(get_config_file()))
def save():
'''
Saves the configuration data to the configuration file
'''
"""Saves the configuration data to the configuration file"""
check()
try:
@ -109,10 +114,9 @@ def save():
except json.JSONDecodeError:
logger.warn('Failed to write to configuration file.')
def reload():
'''
Reloads the configuration data in memory from the file
'''
"""Reloads the configuration data in memory from the file"""
check()
try:
with open(get_config_file(), 'r', encoding="utf8") as configfile:
@ -121,28 +125,24 @@ def reload():
pass
#logger.debug('Failed to parse configuration file.')
def get_config():
'''
Gets the entire configuration as an array
'''
"""Gets the entire configuration as an array"""
return _config
def set_config(config):
'''
Sets the configuration to the array in arguments
'''
"""Sets the configuration to the array in arguments"""
global _config
_config = config
def get_config_file():
'''
Returns the absolute path to the configuration file
'''
"""Returns the absolute path to the configuration file"""
return _configfile
def set_config_file(configfile):
'''
Sets the path to the configuration file
'''
"""Sets the path to the configuration file."""
global _configfile
_configfile = os.abs.abspath(configfile)

View File

@ -0,0 +1,2 @@
from . import plaintextdelete
delete_plaintext = plaintextdelete.delete_plaintext

View File

@ -0,0 +1,36 @@
"""Onionr - Private P2P Communication.
Delete plaintext blocks, used when plaintext is disabled in config
"""
from onionrblocks import onionrblockapi
from coredb import blockmetadb
from onionrstorage.removeblock import remove_block
import onionrstorage
"""
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/>.
"""
def delete_plaintext(dont_delete: bool):
"""Delete, but do not blacklist, plaintext blocks."""
if dont_delete:
return
block_list = blockmetadb.get_block_list()
for block in block_list:
block = onionrblockapi.Block(hash=block)
if not block.isEncrypted:
remove_block(block.hash)
onionrstorage.deleteBlock(block.hash)

View File

@ -1,9 +1,14 @@
'''
"""
Onionr - Private P2P Communication
This module works with information relating to blocks stored on the node
'''
'''
"""
import sqlite3
from etc import onionrvalues
from . import expiredblocks, updateblockinfo, add
from .. import dbfiles
"""
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
@ -16,19 +21,16 @@
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 sqlite3
from etc import onionrvalues
from . import expiredblocks, updateblockinfo, add
from .. import dbfiles
"""
update_block_info = updateblockinfo.update_block_info
add_to_block_DB = add.add_to_block_DB
def get_block_list(dateRec = None, unsaved = False):
'''
"""
Get list of our blocks
'''
"""
if dateRec == None:
dateRec = 0
@ -44,10 +46,11 @@ def get_block_list(dateRec = None, unsaved = False):
conn.close()
return rows
def get_block_date(blockHash):
'''
"""
Returns the date a block was received
'''
"""
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT)
c = conn.cursor()
@ -60,10 +63,11 @@ def get_block_date(blockHash):
conn.close()
return None
def get_blocks_by_type(blockType, orderDate=True):
'''
"""
Returns a list of blocks by the type
'''
"""
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT)
c = conn.cursor()
@ -80,4 +84,5 @@ def get_blocks_by_type(blockType, orderDate=True):
for i in row:
rows.append(i)
conn.close()
return rows
return rows

View File

@ -95,7 +95,7 @@ class Block:
# Check for replay attacks
try:
if epoch.get_epoch() - blockmetadb.get_block_date(self.hash) > 60:
if not cryptoutils.replay_validator(self.bmetadata['rply']): raise onionrexceptions.ReplayAttack
if not cryptoutils.replay_validator(self.bmetadata['rply']): raise onionrexceptions.ReplayAttack
except (AssertionError, KeyError, TypeError, onionrexceptions.ReplayAttack) as e:
if not self.bypassReplayCheck:
# Zero out variables to prevent reading of replays
@ -187,7 +187,7 @@ class Block:
self.date = datetime.datetime.fromtimestamp(self.getDate())
self.valid = True
if self.autoDecrypt:
self.decrypt()
@ -462,61 +462,6 @@ class Block:
return self
# static functions
def getBlocks(type = None, signer = None, signed = None, reverse = False, limit = None):
'''
Returns a list of Block objects based on supplied filters
Inputs:
- type (str): filters by block type
- signer (str/list): filters by signer (one in the list has to be a signer)
- signed (bool): filters out by whether or not the block is signed
- reverse (bool): reverses the list if True
Outputs:
- (list): a list of Block objects that match the input
'''
try:
relevant_blocks = list()
blocks = (blockmetadb.get_block_list() if type is None else blockmetadb.get_blocks_by_type(type))
for block in blocks:
if Block.exists(block):
block = Block(block)
relevant = True
if (not signed is None) and (block.isSigned() != bool(signed)):
relevant = False
if not signer is None:
if isinstance(signer, (str,)):
signer = [signer]
if isinstance(signer, (bytes,)):
signer = [signer.decode()]
isSigner = False
for key in signer:
if block.isSigner(key):
isSigner = True
break
if not isSigner:
relevant = False
if relevant and (limit is None or len(relevant_Blocks) <= int(limit)):
relevant_blocks.append(block)
if bool(reverse):
relevant_blocks.reverse()
return relevant_blocks
except Exception as e:
logger.debug('Failed to get blocks.', error = e)
return list()
def exists(bHash):
'''
Checks if a block is saved to file or not
@ -536,7 +481,7 @@ class Block:
if isinstance(bHash, Block):
bHash = bHash.getHash()
ret = isinstance(onionrstorage.getData(bHash), type(None))
return not ret

View File

@ -19,7 +19,6 @@
'''
import os
from . import identifyhome
from onionrsetup import dbcreator
import filepaths
home = identifyhome.identify_home()
@ -31,6 +30,8 @@ def create_dirs():
if not os.path.exists(path):
os.mkdir(path)
from onionrsetup import dbcreator
for db in dbcreator.create_funcs:
try:
db()

View File

@ -3,5 +3,3 @@
Onionr has two test suites, this directory's unittests and integration tests.
In these unittests, be careful to manage import order. The test home directory environment variable needs to be set before most imports.

View File

@ -0,0 +1,28 @@
#!/usr/bin/env python3
import sys, os
sys.path.append(".")
sys.path.append("src/")
import unittest, uuid
import json
TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/'
print("Test directory:", TEST_DIR)
os.environ["ONIONR_HOME"] = TEST_DIR
from utils import identifyhome, createdirs
from onionrsetup import setup_config
createdirs.create_dirs()
setup_config()
import config
from coredb import blockmetadb
from onionrblocks.insert import insert_block
class TestTemplate(unittest.TestCase):
def test_plaintext_config(self):
b1 = insert_block('test block')
self.assertIn(b1, blockmetadb.get_block_list())
config.set('general.store_plaintext_blocks', False)
self.assertNotIn(b1, blockmetadb.get_block_list())
unittest.main()

25
tests/test_template.py Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
import sys, os
sys.path.append(".")
sys.path.append("src/")
import unittest, uuid
import json
TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/'
print("Test directory:", TEST_DIR)
os.environ["ONIONR_HOME"] = TEST_DIR
from utils import identifyhome, createdirs
from onionrsetup import setup_config
createdirs.create_dirs()
setup_config()
class TestTemplate(unittest.TestCase):
'''
Tests both the onionrusers class and the contactmanager (which inherits it)
'''
def test_true(self):
self.assertTrue(True)
unittest.main()