added motd system, reworked handling of bytes in signatures

master
Kevin Froman 2019-10-07 21:32:33 -05:00
parent 31825bfad7
commit 695f334297
11 changed files with 80 additions and 27 deletions

View File

@ -30,6 +30,7 @@ def register_private_blueprints(private_api, app):
app.register_blueprint(insertblock.ib) app.register_blueprint(insertblock.ib)
app.register_blueprint(miscclientapi.getblocks.client_get_blocks) app.register_blueprint(miscclientapi.getblocks.client_get_blocks)
app.register_blueprint(miscclientapi.endpoints.PrivateEndpoints(private_api).private_endpoints_bp) 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(onionrsitesapi.site_api)
app.register_blueprint(apiutils.shutdown.shutdown_bp) app.register_blueprint(apiutils.shutdown.shutdown_bp)
app.register_blueprint(miscclientapi.staticfiles.static_files_bp) app.register_blueprint(miscclientapi.staticfiles.static_files_bp)

View File

@ -1 +1 @@
from . import getblocks, staticfiles, endpoints from . import getblocks, staticfiles, endpoints, motd

View File

@ -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"})

View File

@ -17,12 +17,14 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import unpaddedbase32
import binascii import binascii
import logger, config, onionrexceptions, nacl.exceptions import logger, config, onionrexceptions, nacl.exceptions
import json, os, sys, datetime, base64, onionrstorage import json, os, sys, datetime, base64, onionrstorage
from onionrusers import onionrusers from onionrusers import onionrusers
from onionrutils import stringvalidators, epoch from onionrutils import stringvalidators, epoch
from coredb import blockmetadb from coredb import blockmetadb
from onionrutils import bytesconverter
from onionrstorage import removeblock from onionrstorage import removeblock
import onionrblocks import onionrblocks
from onionrcrypto import encryption, cryptoutils as cryptoutils, signing 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 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 self.validSig = True
else: else:
self.validSig = False self.validSig = False
@ -175,7 +179,7 @@ class Block:
self.signer = self.getHeader('signer', None) self.signer = self.getHeader('signer', None)
self.signature = self.getHeader('sig', None) self.signature = self.getHeader('sig', None)
# signed data is jsonMeta + block content (no linebreak) # 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.date = blockmetadb.get_block_date(self.getHash())
self.claimedTime = self.getHeader('time', None) self.claimedTime = self.getHeader('time', None)
@ -328,7 +332,7 @@ class Block:
- (str): the contents of the block - (str): the contents of the block
''' '''
return str(self.bcontent) return self.bcontent
def getDate(self): def getDate(self):
''' '''
@ -401,7 +405,7 @@ class Block:
Outputs: Outputs:
- (bool): whether or not the signer of the block is the signer inputted - (bool): whether or not the signer of the block is the signer inputted
''' '''
signer = unpaddedbase32.repad(bytesconverter.str_to_bytes(signer))
try: try:
if (not self.isSigned()) or (not stringvalidators.validate_pub_key(signer)): if (not self.isSigned()) or (not stringvalidators.validate_pub_key(signer)):
return False return False

View File

@ -143,7 +143,7 @@ kill_daemon.onionr_help = "Gracefully stops the Onionr API servers"
def start(input: bool = False, override: bool = False): 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 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: 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: else:
if not onionrvalues.DEVELOPMENT_MODE: if not onionrvalues.DEVELOPMENT_MODE:
lockFile = open(filepaths.lock_file, 'w') lockFile = open(filepaths.lock_file, 'w')

View File

@ -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"

View File

@ -18,6 +18,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
from typing import Callable from typing import Callable
from .. import onionrstatistics, version, daemonlaunch, keyadders, openwebinterface from .. import onionrstatistics, version, daemonlaunch, keyadders, openwebinterface
from .. import banblocks # Command to blacklist a block by its hash from .. import banblocks # Command to blacklist a block by its hash
from .. import filecommands # commands to share files with onionr 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 softreset # command to delete onionr blocks
from .. import restartonionr # command to restart Onionr from .. import restartonionr # command to restart Onionr
from .. import runtimetestcmd from .. import runtimetestcmd
from .. import motdcreator
import onionrexceptions import onionrexceptions
from onionrutils import importnewblocks # func to import new blocks from onionrutils import importnewblocks # func to import new blocks
from onionrplugins import onionrevents as events from onionrplugins import onionrevents as events
@ -57,7 +60,8 @@ def get_arguments()->dict:
('resetplugins', 'reset-plugins'): resetplugins.reset, ('resetplugins', 'reset-plugins'): resetplugins.reset,
('reset-tor-node-transport',): resettor.reset_tor_key_pair, ('reset-tor-node-transport',): resettor.reset_tor_key_pair,
('soft-reset', 'softreset'): softreset.soft_reset, ('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 return args

View File

@ -27,7 +27,6 @@ def ed_verify(data, key, sig, encodedData=True):
try: try:
key = nacl.signing.VerifyKey(key=key, encoder=nacl.encoding.Base32Encoder) key = nacl.signing.VerifyKey(key=key, encoder=nacl.encoding.Base32Encoder)
except nacl.exceptions.ValueError: except nacl.exceptions.ValueError:
#logger.debug('Signature by unknown key (cannot reverse hash)')
return False return False
except binascii.Error: except binascii.Error:
logger.warn('Could not load key for verification, invalid padding') 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() data = data.encode()
except AttributeError: except AttributeError:
pass pass
if encodedData: try:
try: retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding
retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding except nacl.exceptions.BadSignatureError:
except nacl.exceptions.BadSignatureError: pass
pass
else:
try:
retData = key.verify(data, sig)
except nacl.exceptions.BadSignatureError:
pass
return retData return retData

View File

@ -140,6 +140,17 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card motdCard">
<header class="card-header">
<p class="card-header-title" title="message of the day">
Onionr MOTD
</p>
</header>
<div class="card-content">
<div class="content motdContent">
</div>
</div>
</div>
</div> </div>
<div class="column"> <div class="column">
<!--Statistics Card--> <!--Statistics Card-->
@ -148,13 +159,6 @@
<p class="card-header-title"> <p class="card-header-title">
Statistics Statistics
</p> </p>
<div class="field">
<div class="is-pulled-right">
<a class="button is-link" id='refreshStats'>
Refresh Stats
</a>
</div>
</div>
</header> </header>
<div class="card-content"> <div class="card-content">
<div class="content"> <div class="content">

View File

@ -9,3 +9,7 @@
#refreshStats{ #refreshStats{
margin: 5px; margin: 5px;
} }
.motdCard{
margin-top: 1em;
}

View File

@ -13,8 +13,9 @@
<b>Contributors:</b> <b>Contributors:</b>
<ul> <ul>
<li><a href="https://invisamage.com/">Travis Kipp</a> (web UI and CSS)</li> <li><a href="https://invisamage.com/">Travis Kipp</a> web UI and CSS</li>
<li><a href="https://k7dxs.net/">Duncan Simpson</a> Packaging help</li> <li><a href="https://k7dxs.net/">Duncan Simpson</a> packaging help</li>
<li><a href="https://www.siue.edu/~njohnag/">Nicholas Johnson</a> bug fixes</li>
</ul> </ul>
<br> <br>