added motd system, reworked handling of bytes in signatures
parent
31825bfad7
commit
695f334297
|
@ -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)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
from . import getblocks, staticfiles, endpoints
|
from . import getblocks, staticfiles, endpoints, motd
|
|
@ -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"})
|
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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"
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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">
|
||||||
|
|
|
@ -9,3 +9,7 @@
|
||||||
#refreshStats{
|
#refreshStats{
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.motdCard{
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue