From 695f334297a0d3cc56ec14b2d89eecf79c0f3c58 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Mon, 7 Oct 2019 21:32:33 -0500 Subject: [PATCH] added motd system, reworked handling of bytes in signatures --- .../private/register_private_blueprints.py | 1 + onionr/httpapi/miscclientapi/__init__.py | 2 +- onionr/httpapi/miscclientapi/motd/__init__.py | 27 +++++++++++++++++++ onionr/onionrblocks/onionrblockapi.py | 12 ++++++--- onionr/onionrcommands/daemonlaunch.py | 2 +- onionr/onionrcommands/motdcreator.py | 15 +++++++++++ onionr/onionrcommands/parser/arguments.py | 6 ++++- onionr/onionrcrypto/signing/__init__.py | 15 +++-------- static-data/www/private/index.html | 18 ++++++++----- static-data/www/private/main.css | 4 +++ static-data/www/shared/about.html | 5 ++-- 11 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 onionr/httpapi/miscclientapi/motd/__init__.py create mode 100644 onionr/onionrcommands/motdcreator.py diff --git a/onionr/apiservers/private/register_private_blueprints.py b/onionr/apiservers/private/register_private_blueprints.py index 0cb463f5..f6d03e37 100644 --- a/onionr/apiservers/private/register_private_blueprints.py +++ b/onionr/apiservers/private/register_private_blueprints.py @@ -30,6 +30,7 @@ def register_private_blueprints(private_api, app): app.register_blueprint(insertblock.ib) app.register_blueprint(miscclientapi.getblocks.client_get_blocks) app.register_blueprint(miscclientapi.endpoints.PrivateEndpoints(private_api).private_endpoints_bp) + app.register_blueprint(miscclientapi.motd.bp) app.register_blueprint(onionrsitesapi.site_api) app.register_blueprint(apiutils.shutdown.shutdown_bp) app.register_blueprint(miscclientapi.staticfiles.static_files_bp) diff --git a/onionr/httpapi/miscclientapi/__init__.py b/onionr/httpapi/miscclientapi/__init__.py index 6ea8ea0f..dadcb97c 100644 --- a/onionr/httpapi/miscclientapi/__init__.py +++ b/onionr/httpapi/miscclientapi/__init__.py @@ -1 +1 @@ -from . import getblocks, staticfiles, endpoints \ No newline at end of file +from . import getblocks, staticfiles, endpoints, motd \ No newline at end of file diff --git a/onionr/httpapi/miscclientapi/motd/__init__.py b/onionr/httpapi/miscclientapi/motd/__init__.py new file mode 100644 index 00000000..ad57b91a --- /dev/null +++ b/onionr/httpapi/miscclientapi/motd/__init__.py @@ -0,0 +1,27 @@ +from flask import Blueprint +from flask import Response +import unpaddedbase32 + +from coredb import blockmetadb +import onionrblocks +from etc import onionrvalues +import config +from onionrutils import bytesconverter + +bp = Blueprint('motd', __name__) + +signer = config.get("motd.motd_key", onionrvalues.MOTD_SIGN_KEY) + +@bp.route('/getmotd') +def get_motd()->Response: + motds = blockmetadb.get_blocks_by_type("motd") + newest_time = 0 + message = "No MOTD currently present." + for x in motds: + bl = onionrblocks.onionrblockapi.Block(x) + if not bl.verifySig() or bl.signer != bytesconverter.bytes_to_str(unpaddedbase32.repad(bytesconverter.str_to_bytes(signer))): continue + if not bl.isSigner(signer): continue + if bl.claimedTime > newest_time: + newest_time = bl.claimedTime + message = bl.bcontent + return Response(message, headers={"Content-Type": "text/plain"}) diff --git a/onionr/onionrblocks/onionrblockapi.py b/onionr/onionrblocks/onionrblockapi.py index f15347f0..a8c2343b 100755 --- a/onionr/onionrblocks/onionrblockapi.py +++ b/onionr/onionrblocks/onionrblockapi.py @@ -17,12 +17,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' +import unpaddedbase32 import binascii import logger, config, onionrexceptions, nacl.exceptions import json, os, sys, datetime, base64, onionrstorage from onionrusers import onionrusers from onionrutils import stringvalidators, epoch from coredb import blockmetadb +from onionrutils import bytesconverter from onionrstorage import removeblock import onionrblocks from onionrcrypto import encryption, cryptoutils as cryptoutils, signing @@ -127,7 +129,9 @@ class Block: ''' Verify if a block's signature is signed by its claimed signer ''' - if self.signer is None or signing.ed_verify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True): + if self.signer is None: + return False + if signing.ed_verify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True): self.validSig = True else: self.validSig = False @@ -175,7 +179,7 @@ class Block: self.signer = self.getHeader('signer', None) self.signature = self.getHeader('sig', None) # signed data is jsonMeta + block content (no linebreak) - self.signedData = (None if not self.isSigned() else self.getHeader('meta') + self.getContent()) + self.signedData = (None if not self.isSigned() else self.getHeader('meta').encode() + self.getContent()) self.date = blockmetadb.get_block_date(self.getHash()) self.claimedTime = self.getHeader('time', None) @@ -328,7 +332,7 @@ class Block: - (str): the contents of the block ''' - return str(self.bcontent) + return self.bcontent def getDate(self): ''' @@ -401,7 +405,7 @@ class Block: Outputs: - (bool): whether or not the signer of the block is the signer inputted ''' - + signer = unpaddedbase32.repad(bytesconverter.str_to_bytes(signer)) try: if (not self.isSigned()) or (not stringvalidators.validate_pub_key(signer)): return False diff --git a/onionr/onionrcommands/daemonlaunch.py b/onionr/onionrcommands/daemonlaunch.py index 590fcb33..cfb86ebd 100755 --- a/onionr/onionrcommands/daemonlaunch.py +++ b/onionr/onionrcommands/daemonlaunch.py @@ -143,7 +143,7 @@ kill_daemon.onionr_help = "Gracefully stops the Onionr API servers" def start(input: bool = False, override: bool = False): """If no lock file, make one and start onionr, error if there is and its not overridden""" if os.path.exists(filepaths.lock_file) 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 filepaths.lock_file & try again).', terminal=True) + 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).', terminal=True) else: if not onionrvalues.DEVELOPMENT_MODE: lockFile = open(filepaths.lock_file, 'w') diff --git a/onionr/onionrcommands/motdcreator.py b/onionr/onionrcommands/motdcreator.py new file mode 100644 index 00000000..93586f74 --- /dev/null +++ b/onionr/onionrcommands/motdcreator.py @@ -0,0 +1,15 @@ +import onionrblocks + +def motd_creator(): + """Create a new MOTD message for the Onionr network""" + motd = '' + new = '' + print('Enter a new MOTD, quit on a new line:') + while new != 'quit': + new = input() + if new != 'quit': + motd += new + bl = onionrblocks.insert(motd, header='motd', sign=True) + print(f"inserted in {bl}") + +motd_creator.onionr_help = "Create a new MOTD message for the onionr network" diff --git a/onionr/onionrcommands/parser/arguments.py b/onionr/onionrcommands/parser/arguments.py index 3cd110e8..2011daa1 100644 --- a/onionr/onionrcommands/parser/arguments.py +++ b/onionr/onionrcommands/parser/arguments.py @@ -18,6 +18,7 @@ along with this program. If not, see . ''' from typing import Callable + from .. import onionrstatistics, version, daemonlaunch, keyadders, openwebinterface from .. import banblocks # Command to blacklist a block by its hash from .. import filecommands # commands to share files with onionr @@ -28,6 +29,8 @@ from .. import resetplugins # command to reinstall default plugins from .. import softreset # command to delete onionr blocks from .. import restartonionr # command to restart Onionr from .. import runtimetestcmd +from .. import motdcreator + import onionrexceptions from onionrutils import importnewblocks # func to import new blocks from onionrplugins import onionrevents as events @@ -57,7 +60,8 @@ def get_arguments()->dict: ('resetplugins', 'reset-plugins'): resetplugins.reset, ('reset-tor-node-transport',): resettor.reset_tor_key_pair, ('soft-reset', 'softreset'): softreset.soft_reset, - ('runtime-test', 'runtimetest'): runtimetestcmd.do_runtime_test + ('runtime-test', 'runtimetest'): runtimetestcmd.do_runtime_test, + ('makemotd', 'make-motd'): motdcreator.motd_creator } return args diff --git a/onionr/onionrcrypto/signing/__init__.py b/onionr/onionrcrypto/signing/__init__.py index 3562efe0..61a9616e 100644 --- a/onionr/onionrcrypto/signing/__init__.py +++ b/onionr/onionrcrypto/signing/__init__.py @@ -27,7 +27,6 @@ def ed_verify(data, key, sig, encodedData=True): try: key = nacl.signing.VerifyKey(key=key, encoder=nacl.encoding.Base32Encoder) except nacl.exceptions.ValueError: - #logger.debug('Signature by unknown key (cannot reverse hash)') return False except binascii.Error: logger.warn('Could not load key for verification, invalid padding') @@ -38,14 +37,8 @@ def ed_verify(data, key, sig, encodedData=True): data = data.encode() except AttributeError: pass - if encodedData: - try: - retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding - except nacl.exceptions.BadSignatureError: - pass - else: - try: - retData = key.verify(data, sig) - except nacl.exceptions.BadSignatureError: - pass + try: + retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding + except nacl.exceptions.BadSignatureError: + pass return retData \ No newline at end of file diff --git a/static-data/www/private/index.html b/static-data/www/private/index.html index 88f66ef8..d740961d 100755 --- a/static-data/www/private/index.html +++ b/static-data/www/private/index.html @@ -140,6 +140,17 @@ +
+
+

+ Onionr MOTD +

+
+
+
+
+
+
@@ -148,13 +159,6 @@

Statistics

-
diff --git a/static-data/www/private/main.css b/static-data/www/private/main.css index 7a80bef2..2d7ed83f 100755 --- a/static-data/www/private/main.css +++ b/static-data/www/private/main.css @@ -8,4 +8,8 @@ } #refreshStats{ margin: 5px; +} + +.motdCard{ + margin-top: 1em; } \ No newline at end of file diff --git a/static-data/www/shared/about.html b/static-data/www/shared/about.html index bc8fafe8..e4b5f32b 100644 --- a/static-data/www/shared/about.html +++ b/static-data/www/shared/about.html @@ -13,8 +13,9 @@ Contributors: