diff --git a/onionr.sh b/onionr.sh index ef955eec..461da32a 100755 --- a/onionr.sh +++ b/onionr.sh @@ -1,5 +1,6 @@ #!/bin/sh ORIG_ONIONR_RUN_DIR=`pwd` +export ORIG_ONIONR_RUN_DIR cd "$(dirname "$0")" cd onionr -./__init__.py "$@" +./__init__.py "$@" \ No newline at end of file diff --git a/onionr/httpapi/onionrsitesapi/sitefiles.py b/onionr/httpapi/onionrsitesapi/sitefiles.py index 764ccae0..7ce01964 100644 --- a/onionr/httpapi/onionrsitesapi/sitefiles.py +++ b/onionr/httpapi/onionrsitesapi/sitefiles.py @@ -1,9 +1,13 @@ from typing import Union import tarfile import io +import os from coredb import blockmetadb from onionrblocks import onionrblockapi +from onionrblocks import insert +from onionrtypes import UserID, DeterministicKeyPassphrase # Import types. Just for type hiting +from onionrcrypto import generate def find_site_gzip(user_id: str)->str: sites = blockmetadb.get_blocks_by_type('osite') @@ -20,3 +24,18 @@ def get_file(user_id, file)->Union[bytes, None]: if file.name == file: return site.extractfile(file) return None + +def create_site(admin_pass: DeterministicKeyPassphrase, directory:str='.')->UserID: + public_key, private_key = generate.generate_deterministic(admin_pass) + + raw_tar = io.BytesIO() + + tar = tarfile.open(mode='x:gz', fileobj=raw_tar) + tar.add(directory) + tar.close() + + raw_tar.seek(0) + + insert.insert(raw_tar.read()) + + return public_key \ No newline at end of file diff --git a/onionr/onionrblocks/insert.py b/onionr/onionrblocks/insert.py index 4416291d..65b2befd 100644 --- a/onionr/onionrblocks/insert.py +++ b/onionr/onionrblocks/insert.py @@ -12,15 +12,24 @@ import coredb import onionrproofs from onionrproofs import subprocesspow import logger +from onionrtypes import UserIDSecretKey def insert_block(data: Union[str, bytes], header: str ='txt', sign: bool =False, encryptType:str ='', symKey:str ='', asymPeer:str ='', meta:dict = {}, - expire:Union[int, None] =None, disableForward:bool =False)->Union[str,bool]: + expire:Union[int, None] =None, disableForward:bool =False, + signing_key:UserIDSecretKey ='')->Union[str,bool]: """ Inserts a block into the network encryptType must be specified to encrypt a block """ + our_private_key = crypto.priv_key + our_pub_key = crypto.pub_key + + if signingKey != '': + our_private_key = signing_key + our_pub_key = crypto.cryptoutils.get_pub_key_from_priv(our_private_key) + use_subprocess = powchoice.use_subprocess(config) storage_counter = storagecounter.StorageCounter() allocationReachedMessage = 'Cannot insert block, disk allocation reached.' @@ -56,6 +65,7 @@ def insert_block(data: Union[str, bytes], header: str ='txt', signature = '' signer = '' metadata = {} + # metadata is full block metadata, meta is internal, user specified metadata # only use header if not set in provided meta @@ -76,7 +86,7 @@ def insert_block(data: Union[str, bytes], header: str ='txt', if encryptType == 'asym': meta['rply'] = createTime # Duplicate the time in encrypted messages to prevent replays - if not disableForward and sign and asymPeer != crypto.pub_key: + if not disableForward and sign and asymPeer != our_pub_key: try: forwardEncrypted = onionrusers.OnionrUser(asymPeer).forwardEncrypt(data) data = forwardEncrypted[0] @@ -91,8 +101,8 @@ def insert_block(data: Union[str, bytes], header: str ='txt', jsonMeta = json.dumps(meta) plaintextMeta = jsonMeta if sign: - signature = crypto.signing.ed_sign(jsonMeta.encode() + data, key=crypto.priv_key, encodeResult=True) - signer = crypto.pub_key + signature = crypto.signing.ed_sign(jsonMeta.encode() + data, key=our_private_key, encodeResult=True) + signer = our_pub_key if len(jsonMeta) > 1000: raise onionrexceptions.InvalidMetadata('meta in json encoded form must not exceed 1000 bytes') diff --git a/onionr/onionrcommands/parser/__init__.py b/onionr/onionrcommands/parser/__init__.py index ead84558..69285b25 100644 --- a/onionr/onionrcommands/parser/__init__.py +++ b/onionr/onionrcommands/parser/__init__.py @@ -18,6 +18,8 @@ along with this program. If not, see . ''' import sys +import os + from etc import onionrvalues import logger, onionrexceptions import onionrplugins @@ -69,6 +71,9 @@ def register(): if cmd.replace('--', '').lower() == 'help': is_help_cmd = True try: + try: + if cmd != 'start': os.chdir(os.environ['ORIG_ONIONR_RUN_DIR']) + except KeyError: pass arguments.get_func(cmd)() except onionrexceptions.NotFound: if not register_plugin_commands(cmd) and not is_help_cmd: diff --git a/onionr/onionrcommands/parser/arguments.py b/onionr/onionrcommands/parser/arguments.py index 2011daa1..e9b0df49 100644 --- a/onionr/onionrcommands/parser/arguments.py +++ b/onionr/onionrcommands/parser/arguments.py @@ -30,6 +30,7 @@ from .. import softreset # command to delete onionr blocks from .. import restartonionr # command to restart Onionr from .. import runtimetestcmd from .. import motdcreator +from httpapi import onionrsitesapi import onionrexceptions from onionrutils import importnewblocks # func to import new blocks @@ -48,7 +49,8 @@ def get_arguments()->dict: ('add-address', 'addaddress', 'addadder'): keyadders.add_address, ('openhome', 'gui', 'openweb', 'open-home', 'open-web'): openwebinterface.open_home, ('get-url', 'url', 'get-web'): openwebinterface.get_url, - ('add-site', 'addsite', 'addhtml', 'add-html'): filecommands.add_html, + ('addhtml', 'add-html'): filecommands.add_html, + ('addsite', 'add-site'): onionrsitesapi.sitefiles.create_site, ('addfile', 'add-file'): filecommands.add_file, ('get-file', 'getfile'): filecommands.get_file, ('export-block', 'exportblock'): exportblocks.export_block, diff --git a/onionr/onionrcrypto/cryptoutils/__init__.py b/onionr/onionrcrypto/cryptoutils/__init__.py index 87bcd2d3..e90854b8 100644 --- a/onionr/onionrcrypto/cryptoutils/__init__.py +++ b/onionr/onionrcrypto/cryptoutils/__init__.py @@ -1,6 +1,8 @@ from . import safecompare, replayvalidation, randomshuffle, verifypow +from . import getpubfrompriv replay_validator = replayvalidation.replay_timestamp_validation random_shuffle = randomshuffle.random_shuffle safe_compare = safecompare.safe_compare -verify_POW = verifypow.verify_POW \ No newline at end of file +verify_POW = verifypow.verify_POW +get_pub_key_from_priv = getpubfrompriv.get_pub_key_from_priv diff --git a/onionr/onionrcrypto/cryptoutils/getpubfrompriv.py b/onionr/onionrcrypto/cryptoutils/getpubfrompriv.py new file mode 100644 index 00000000..8bb8d7d2 --- /dev/null +++ b/onionr/onionrcrypto/cryptoutils/getpubfrompriv.py @@ -0,0 +1,6 @@ +from nacl import signing, encoding + +from onionrtypes import UserID, UserIDSecretKey + +def get_pub_key_from_priv(priv_key: UserIDSecretKey, raw_encoding:bool=False)->UserID: + return signing.SigningKey(priv_key, encoder=encoding.Base32Encoder).verify_key.encode(encoding.Base32Encoder) diff --git a/onionr/onionrcrypto/generate.py b/onionr/onionrcrypto/generate.py index 4523aab6..7fab9c16 100644 --- a/onionr/onionrcrypto/generate.py +++ b/onionr/onionrcrypto/generate.py @@ -24,4 +24,4 @@ def generate_deterministic(passphrase, bypassCheck=False): key = kdf(32, passphrase, salt, opslimit=ops, memlimit=mem) # Generate seed for ed25519 key key = nacl.signing.SigningKey(key) - return (key.verify_key.encode(nacl.encoding.Base32Encoder).decode(), key.encode(nacl.encoding.Base32Encoder).decode()) \ No newline at end of file + return (key.verify_key.encode(nacl.encoding.Base32Encoder).decode(), key.encode(nacl.encoding.Base32Encoder).decode()) diff --git a/onionr/onionrcrypto/signing.py b/onionr/onionrcrypto/signing.py deleted file mode 100644 index e69de29b..00000000 diff --git a/onionr/onionrcrypto/signing/__init__.py b/onionr/onionrcrypto/signing/__init__.py index 61a9616e..d7c9d748 100644 --- a/onionr/onionrcrypto/signing/__init__.py +++ b/onionr/onionrcrypto/signing/__init__.py @@ -41,4 +41,4 @@ def ed_verify(data, key, sig, encodedData=True): 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 + return retData diff --git a/onionr/onionrtypes/__init__.py b/onionr/onionrtypes/__init__.py new file mode 100644 index 00000000..a1dbbf95 --- /dev/null +++ b/onionr/onionrtypes/__init__.py @@ -0,0 +1,6 @@ +from typing import NewType + +UserID = NewType('UserID', str) +UserIDSecretKey = NewType('UserIDSecretKey', str) + +DeterministicKeyPassphrase = NewType('DeterministicKeyPassphrase', str) \ No newline at end of file diff --git a/tests/test_highlevelcrypto.py b/tests/test_highlevelcrypto.py index 35f395ed..f13e7398 100755 --- a/tests/test_highlevelcrypto.py +++ b/tests/test_highlevelcrypto.py @@ -93,6 +93,11 @@ class OnionrCryptoTests(unittest.TestCase): # Try to encrypt arbitrary bytes crypto.encryption.pub_key_encrypt(os.urandom(32), keyPair2[0]) + def test_pub_from_priv(self): + priv = nacl.signing.SigningKey.generate().encode(encoder=nacl.encoding.Base32Encoder) + pub = crypto.cryptoutils.getpubfrompriv.get_pub_key_from_priv(priv) + self.assertTrue(stringvalidators.validate_pub_key(pub)) + def test_deterministic(self): password = os.urandom(32) gen = crypto.generate_deterministic(password)