diff --git a/src/__init__.py b/src/__init__.py index 7ee2fd0e..2120af0b 100755 --- a/src/__init__.py +++ b/src/__init__.py @@ -70,7 +70,6 @@ createdirs.create_dirs() import bigbrother # noqa from onionrcommands import parser # noqa from onionrplugins import onionrevents as events # noqa -from onionrblocks.deleteplaintext import delete_plaintext_no_blacklist # noqa setup.setup_config() @@ -84,8 +83,6 @@ if config.get('advanced.security_auditing', True): except onionrexceptions.PythonVersion: pass -if not config.get('general.store_plaintext_blocks', True): - delete_plaintext_no_blacklist() setup.setup_default_plugins() diff --git a/src/apiservers/private/__init__.py b/src/apiservers/private/__init__.py index a480ce96..61f2f40f 100644 --- a/src/apiservers/private/__init__.py +++ b/src/apiservers/private/__init__.py @@ -68,7 +68,6 @@ class PrivateAPI: self.httpServer = '' self.queueResponse = {} - self.get_block_data = httpapi.apiutils.GetBlockData(self) register_private_blueprints.register_private_blueprints(self, app) httpapi.load_plugin_blueprints(app) self.app = app diff --git a/src/apiservers/private/register_private_blueprints.py b/src/apiservers/private/register_private_blueprints.py index bbbad6d7..40be1ad8 100644 --- a/src/apiservers/private/register_private_blueprints.py +++ b/src/apiservers/private/register_private_blueprints.py @@ -6,7 +6,7 @@ from threading import Thread from gevent import sleep from httpapi import security, friendsapi, configapi -from httpapi import miscclientapi, onionrsitesapi, apiutils +from httpapi import miscclientapi, apiutils from httpapi import themeapi from httpapi import fileoffsetreader from httpapi.sse.private import private_sse_blueprint @@ -35,8 +35,6 @@ def register_private_blueprints(private_api, app): app.register_blueprint(configapi.config_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(apiutils.shutdown.shutdown_bp) app.register_blueprint(miscclientapi.staticfiles.static_files_bp) app.register_blueprint(themeapi.theme_blueprint) diff --git a/src/coredb/__init__.py b/src/coredb/__init__.py index d60f2150..6d5a3268 100644 --- a/src/coredb/__init__.py +++ b/src/coredb/__init__.py @@ -1 +1 @@ -from . import keydb, blockmetadb \ No newline at end of file +from . import keydb \ No newline at end of file diff --git a/src/coredb/blockmetadb/__init__.py b/src/coredb/blockmetadb/__init__.py deleted file mode 100644 index 10e36f0a..00000000 --- a/src/coredb/blockmetadb/__init__.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Onionr - Private P2P Communication. - -Work 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 - (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 . -""" - -update_block_info = updateblockinfo.update_block_info -add_to_block_DB = add.add_to_block_DB - - -def get_block_list(date_rec=None, unsaved=False): - """Get list of our blocks.""" - if date_rec is None: - date_rec = 0 - - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - - execute = 'SELECT hash FROM hashes WHERE dateReceived' + \ - ' >= ? ORDER BY dateReceived ASC;' - args = (date_rec,) - rows = list() - for row in c.execute(execute, args): - for i in row: - rows.append(i) - conn.close() - return rows - - -def get_block_date(blockHash): - """Return the date a block was received.""" - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - - execute = 'SELECT dateReceived FROM hashes WHERE hash=?;' - args = (blockHash,) - for row in c.execute(execute, args): - for i in row: - return int(i) - conn.close() - return None - - -def get_blocks_by_type(blockType, orderDate=True): - """Return a list of blocks by the type.""" - - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - - if orderDate: - execute = 'SELECT hash FROM hashes WHERE dataType=? ORDER BY dateReceived;' - else: - execute = 'SELECT hash FROM hashes WHERE dataType=?;' - - args = (blockType,) - rows = list() - - for row in c.execute(execute, args): - for i in row: - rows.append(i) - conn.close() - return rows - diff --git a/src/coredb/blockmetadb/add.py b/src/coredb/blockmetadb/add.py deleted file mode 100644 index ec1ab861..00000000 --- a/src/coredb/blockmetadb/add.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Onionr - Private P2P Communication. - -Add an entry to the block metadata database -""" -import sqlite3 -import secrets -from onionrutils import epoch -from onionrblocks import blockmetadata -from etc import onionrvalues -from .. import dbfiles -from onionrexceptions import BlockMetaEntryExists -""" - 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 . -""" - - -def add_to_block_DB(newHash, selfInsert=False, dataSaved=False): - """ - Add a hash value to the block db - - Should be in hex format! - """ - - if blockmetadata.has_block(newHash): - raise BlockMetaEntryExists - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - currentTime = epoch.get_epoch() + secrets.randbelow(61) - if selfInsert or dataSaved: - selfInsert = 1 - else: - selfInsert = 0 - data = (newHash, currentTime, '', selfInsert) - c.execute( - 'INSERT INTO hashes (hash, dateReceived, dataType, dataSaved) VALUES(?, ?, ?, ?);', data) - conn.commit() - conn.close() diff --git a/src/coredb/blockmetadb/expiredblocks.py b/src/coredb/blockmetadb/expiredblocks.py deleted file mode 100644 index efaa75a4..00000000 --- a/src/coredb/blockmetadb/expiredblocks.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Onionr - Private P2P Communication. - -Get a list of expired blocks still stored -""" -import sqlite3 -from onionrutils import epoch -from .. import dbfiles -from etc import onionrvalues -""" - 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 . -""" - - -def get_expired_blocks(): - """Return a list of expired blocks.""" - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - date = int(epoch.get_epoch()) - - compiled = (date,) - execute = 'SELECT hash FROM hashes WHERE ' + \ - 'expire <= ? ORDER BY dateReceived;' - - rows = list() - for row in c.execute(execute, compiled): - for i in row: - rows.append(i) - conn.close() - return rows diff --git a/src/coredb/blockmetadb/updateblockinfo.py b/src/coredb/blockmetadb/updateblockinfo.py deleted file mode 100644 index 41a67cca..00000000 --- a/src/coredb/blockmetadb/updateblockinfo.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Onionr - Private P2P Communication. - -Update block information in the metadata database by a field name -""" -import sqlite3 - -from .. import dbfiles -from etc import onionrvalues -""" - 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 . -""" - - -def update_block_info(hash, key, data): - """set info associated with a block - - hash - the hash of a block - dateReceived - the date the block was recieved, not necessarily when it was created - decrypted - if we can successfully decrypt the block - dataType - data type of the block - dataFound - if the data has been found for the block - dataSaved - if the data has been saved for the block - sig - defunct - author - defunct - dateClaimed - timestamp claimed inside the block, only as trustworthy as the block author is - expire - expire date for a block - """ - if key not in ('dateReceived', 'decrypted', 'dataType', 'dataFound', - 'dataSaved', 'sig', 'author', 'dateClaimed', 'expire'): - raise ValueError('Key must be in the allowed list') - - conn = sqlite3.connect(dbfiles.block_meta_db, - timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - args = (data, hash) - # Unfortunately, not really possible to prepare this statement - c.execute("UPDATE hashes SET " + key + " = ? where hash = ?;", args) - conn.commit() - conn.close() - - return True diff --git a/src/coredb/dbfiles.py b/src/coredb/dbfiles.py index 3d1e8383..695b89eb 100644 --- a/src/coredb/dbfiles.py +++ b/src/coredb/dbfiles.py @@ -3,8 +3,6 @@ import filepaths home = identifyhome.identify_home() if not home.endswith('/'): home += '/' -block_meta_db = '%sblock-metadata.db' % (home) -block_data_db = '%s/block-data.db' % (filepaths.block_data_location,) address_info_db = '%saddress.db' % (home,) user_id_info_db = '%susers.db' % (home,) forward_keys_db = '%sforward-keys.db' % (home,) diff --git a/src/httpapi/apiutils/__init__.py b/src/httpapi/apiutils/__init__.py index cab13c98..d8c4f227 100644 --- a/src/httpapi/apiutils/__init__.py +++ b/src/httpapi/apiutils/__init__.py @@ -1,3 +1 @@ -from . import shutdown, setbindip, getblockdata - -GetBlockData = getblockdata.GetBlockData \ No newline at end of file +from . import shutdown, setbindip \ No newline at end of file diff --git a/src/httpapi/apiutils/getblockdata.py b/src/httpapi/apiutils/getblockdata.py deleted file mode 100644 index 9da1ee59..00000000 --- a/src/httpapi/apiutils/getblockdata.py +++ /dev/null @@ -1,38 +0,0 @@ -import ujson as json - -from onionrblocks import onionrblockapi -from onionrutils import bytesconverter, stringvalidators -import onionrexceptions -class GetBlockData: - def __init__(self, client_api_inst=None): - return - - def get_block_data(self, bHash, decrypt=False, raw=False, headerOnly=False): - if not stringvalidators.validate_hash(bHash): - raise onionrexceptions.InvalidHexHash( - "block hash not valid hash format") - bl = onionrblockapi.Block(bHash) - if decrypt: - bl.decrypt() - if bl.isEncrypted and not bl.decrypted: - raise ValueError - - if not raw: - if not headerOnly: - retData = {'meta':bl.bheader, 'metadata': bl.bmetadata, 'content': bl.bcontent} - for x in list(retData.keys()): - try: - retData[x] = retData[x].decode() - except AttributeError: - pass - else: - validSig = False - signer = bytesconverter.bytes_to_str(bl.signer) - if bl.isSigned() and stringvalidators.validate_pub_key(signer) and bl.isSigner(signer): - validSig = True - bl.bheader['validSig'] = validSig - bl.bheader['meta'] = '' - retData = {'meta': bl.bheader, 'metadata': bl.bmetadata} - return json.dumps(retData) - else: - return bl.raw \ No newline at end of file diff --git a/src/httpapi/miscclientapi/__init__.py b/src/httpapi/miscclientapi/__init__.py index b850723c..1d917684 100644 --- a/src/httpapi/miscclientapi/__init__.py +++ b/src/httpapi/miscclientapi/__init__.py @@ -1 +1 @@ -from . import staticfiles, endpoints, motd \ No newline at end of file +from . import staticfiles, endpoints \ No newline at end of file diff --git a/src/httpapi/miscclientapi/endpoints.py b/src/httpapi/miscclientapi/endpoints.py index ed10d969..3e91c08c 100644 --- a/src/httpapi/miscclientapi/endpoints.py +++ b/src/httpapi/miscclientapi/endpoints.py @@ -78,10 +78,6 @@ class PrivateEndpoints: subprocess.Popen([SCRIPT_NAME, 'restart']) return Response("bye") - @private_endpoints_bp.route('/gethidden') - def get_hidden_blocks(): - return Response('\n'.join(client_api.publicAPI.hideBlocks)) - @private_endpoints_bp.route('/getuptime') def show_uptime(): diff --git a/src/httpapi/miscclientapi/motd/__init__.py b/src/httpapi/miscclientapi/motd/__init__.py deleted file mode 100644 index ad57b91a..00000000 --- a/src/httpapi/miscclientapi/motd/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -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/src/httpapi/onionrsitesapi/__init__.py b/src/httpapi/onionrsitesapi/__init__.py deleted file mode 100644 index 9526aa76..00000000 --- a/src/httpapi/onionrsitesapi/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Onionr - Private P2P Communication. - -view and interact with onionr sites -""" -import base64 -import binascii -import mimetypes - -import unpaddedbase32 - -from flask import Blueprint, Response, request, abort - -from onionrblocks import onionrblockapi -import onionrexceptions -from onionrutils import stringvalidators -from onionrutils import mnemonickeys -from . import sitefiles -""" - 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 . -""" - - -site_api = Blueprint('siteapi', __name__) - -@site_api.route('/site//', endpoint='site') -def site(name: str)->Response: - """Accept a site 'name', if pubkey then show multi-page site, if hash show single page site""" - resp: str = 'Not Found' - mime_type = 'text/html' - - # If necessary convert the name to base32 from mnemonic - if mnemonickeys.DELIMITER in name: - name = mnemonickeys.get_base32(name) - - # Now make sure the key is regardless a valid base32 format ed25519 key (readding padding if necessary) - if stringvalidators.validate_pub_key(name): - name = unpaddedbase32.repad(name) - resp = sitefiles.get_file(name, 'index.html') - - elif stringvalidators.validate_hash(name): - try: - resp = onionrblockapi.Block(name).bcontent - except onionrexceptions.NoDataAvailable: - abort(404) - except TypeError: - pass - try: - resp = base64.b64decode(resp) - except binascii.Error: - pass - if resp == 'Not Found' or not resp: - abort(404) - return Response(resp) - -@site_api.route('/site//', endpoint='siteFile') -def site_file(name: str, file: str)->Response: - """Accept a site 'name', if pubkey then show multi-page site, if hash show single page site""" - resp: str = 'Not Found' - mime_type = mimetypes.MimeTypes().guess_type(file)[0] - - # If necessary convert the name to base32 from mnemonic - if mnemonickeys.DELIMITER in name: - name = mnemonickeys.get_base32(name) - - # Now make sure the key is regardless a valid base32 format ed25519 key (readding padding if necessary) - if stringvalidators.validate_pub_key(name): - name = unpaddedbase32.repad(name) - resp = sitefiles.get_file(name, file) - - elif stringvalidators.validate_hash(name): - try: - resp = onionrblockapi.Block(name).bcontent - except onionrexceptions.NoDataAvailable: - abort(404) - except TypeError: - pass - try: - resp = base64.b64decode(resp) - except binascii.Error: - pass - if resp == 'Not Found' or not resp: - abort(404) - return Response(resp, mimetype=mime_type) diff --git a/src/httpapi/onionrsitesapi/findsite.py b/src/httpapi/onionrsitesapi/findsite.py deleted file mode 100644 index 6811ae4c..00000000 --- a/src/httpapi/onionrsitesapi/findsite.py +++ /dev/null @@ -1,49 +0,0 @@ -""" - Onionr - Private P2P Communication - - view and interact with onionr sites -""" - -from typing import Union - -import onionrexceptions -from onionrutils import mnemonickeys -from onionrutils import stringvalidators -from coredb import blockmetadb -from onionrblocks.onionrblockapi import Block -from onionrtypes import BlockHash - -""" - 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 . -""" - - -def find_site(user_id: str) -> Union[BlockHash, None]: - """Returns block hash str for latest block for a site by a given user id""" - # If mnemonic delim in key, convert to base32 version - if mnemonickeys.DELIMITER in user_id: - user_id = mnemonickeys.get_base32(user_id) - - if not stringvalidators.validate_pub_key(user_id): - raise onionrexceptions.InvalidPubkey - - found_site = None - sites = blockmetadb.get_blocks_by_type('osite') - - # Find site by searching all site blocks. eww O(N) ☹️, TODO: event based - for site in sites: - site = Block(site) - if site.isSigner(user_id) and site.verifySig(): - found_site = site.hash - return found_site diff --git a/src/httpapi/onionrsitesapi/sitefiles.py b/src/httpapi/onionrsitesapi/sitefiles.py deleted file mode 100644 index f9171926..00000000 --- a/src/httpapi/onionrsitesapi/sitefiles.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Onionr - Private P2P Communication. - -Read onionr site files -""" -from typing import Union, Tuple -import tarfile -import io -import os - -import unpaddedbase32 - -from coredb import blockmetadb -from onionrblocks import onionrblockapi -from onionrblocks import insert - -# Import types. Just for type hiting -from onionrtypes import UserID, DeterministicKeyPassphrase, BlockHash - -from onionrcrypto import generate_deterministic -""" - 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 . -""" - - -def find_site_gzip(user_id: str)->tarfile.TarFile: - """Return verified site tar object""" - sites = blockmetadb.get_blocks_by_type('osite') - user_site = None - unpadded_user = user_id - user_id = unpaddedbase32.repad(user_id) - for site in sites: - block = onionrblockapi.Block(site) - if block.isSigner(user_id) or block.isSigner(unpadded_user): - user_site = block - if not user_site is None: - return tarfile.open(fileobj=io.BytesIO(user_site.bcontent), mode='r') - return None - - -def get_file(user_id, file)->Union[bytes, None]: - """Get a site file content""" - ret_data = "" - site = find_site_gzip(user_id) - - if file.endswith('/'): - file += 'index.html' - if site is None: return None - for t_file in site.getmembers(): - - if t_file.name.replace('./', '') == file: - return site.extractfile(t_file) - return None - - -def create_site(admin_pass: DeterministicKeyPassphrase, directory:str='.')->Tuple[UserID, BlockHash]: - public_key, private_key = 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) - - block_hash = insert(raw_tar.read(), header='osite', signing_key=private_key, sign=True) - - return (public_key, block_hash) diff --git a/src/httpapi/sse/private/__init__.py b/src/httpapi/sse/private/__init__.py index 9d9ffaef..6e812341 100644 --- a/src/httpapi/sse/private/__init__.py +++ b/src/httpapi/sse/private/__init__.py @@ -9,9 +9,6 @@ from gevent import sleep import gevent import ujson -from onionrblocks.onionrblockapi import Block -from coredb.dbfiles import block_meta_db -from coredb.blockmetadb import get_block_list from onionrutils.epoch import get_epoch from .. import wrapper """ @@ -42,27 +39,3 @@ def stream_hello(): sleep(1) return SSEWrapper.handle_sse_request(print_hello) - -@private_sse_blueprint.route('/recentblocks') -def stream_recent_blocks(): - def _compile_json(b_list): - js = {} - block_obj = None - for block in b_list: - block_obj = Block(block) - if block_obj.isEncrypted: - js[block] = 'encrypted' - else: - js[block] = Block(block).btype - return ujson.dumps({"blocks": js}, reject_bytes=True) - - def _stream_recent(): - last_time = Path(block_meta_db).stat().st_ctime - while True: - if Path(block_meta_db).stat().st_ctime != last_time: - last_time = Path(block_meta_db).stat().st_ctime - yield "data: " + _compile_json(get_block_list(get_epoch() - 5)) + "\n\n" - else: - yield "data: none" + "\n\n" - sleep(5) - return SSEWrapper.handle_sse_request(_stream_recent) diff --git a/src/onionrblocks/__init__.py b/src/onionrblocks/__init__.py deleted file mode 100644 index 0e977261..00000000 --- a/src/onionrblocks/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from . import insert -from .insert import time_insert -from .blocklist import BlockList -insert = insert.insert_block -time_insert = time_insert \ No newline at end of file diff --git a/src/onionrblocks/blockdecrypt.py b/src/onionrblocks/blockdecrypt.py deleted file mode 100644 index 5a3aad73..00000000 --- a/src/onionrblocks/blockdecrypt.py +++ /dev/null @@ -1,11 +0,0 @@ -import ujson -import nacl.utils -from nacl.public import PrivateKey, SealedBox - -from .blockmetadata import get_block_metadata_from_data - -def block_decrypt(raw_block) -> DecryptedBlock: - block_header, user_meta, block_data = get_block_metadata_from_data( - raw_block) - - diff --git a/src/onionrblocks/blockimporter.py b/src/onionrblocks/blockimporter.py deleted file mode 100755 index 29fde84f..00000000 --- a/src/onionrblocks/blockimporter.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Onionr - Private P2P Communication. - -Import block data and save it -""" -from onionrexceptions import BlacklistedBlock -from onionrexceptions import DiskAllocationReached -from onionrexceptions import InvalidProof -from onionrexceptions import InvalidMetadata -import logger -from onionrutils import validatemetadata -from onionrutils import bytesconverter -from coredb import blockmetadb -from onionrblocks import blockmetadata -import onionrstorage -import onionrcrypto as crypto -from . import onionrblacklist - -""" - 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 . -""" - - -def import_block_from_data(content): - blacklist = onionrblacklist.OnionrBlackList() - ret_data = False - - content = bytesconverter.str_to_bytes(content) - - data_hash = crypto.hashers.sha3_hash(content) - - if blacklist.inBlacklist(data_hash): - raise BlacklistedBlock(f'%s is a blacklisted block {data_hash}') - - # returns tuple(metadata, meta), meta is also in metadata - metas = blockmetadata.get_block_metadata_from_data(content) - metadata = metas[0] - - # check if metadata is valid - if validatemetadata.validate_metadata(metadata, metas[2]): - # check if POW is enough/correct - if crypto.cryptoutils.verify_POW(content): - logger.info(f'Imported block passed proof, saving: {data_hash}.', - terminal=True) - try: - block_hash = onionrstorage.set_data(content) - except DiskAllocationReached: - logger.warn('Failed to save block due to full disk allocation') - raise - else: - blockmetadb.add_to_block_DB(block_hash, dataSaved=True) - # caches block metadata values to block database - blockmetadata.process_block_metadata(block_hash) - ret_data = block_hash - else: - raise InvalidProof - else: - raise InvalidMetadata - return ret_data diff --git a/src/onionrblocks/blocklist.py b/src/onionrblocks/blocklist.py deleted file mode 100644 index 26c2f925..00000000 --- a/src/onionrblocks/blocklist.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Onionr - Private P2P Communication. - -Get an auto updating list of blocks -""" -from threading import Thread - -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -from utils.identifyhome import identify_home -from coredb.dbfiles import block_meta_db -from coredb.blockmetadb import get_block_list, get_blocks_by_type -from onionrutils.epoch import get_epoch -""" - 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 . -""" - -class BlockList: - def __init__(self, auto_refresh=True, block_type=''): - self.block_type = block_type - self.refresh_db() - self.check_time = get_epoch() - - class Refresher(FileSystemEventHandler): - @staticmethod - def on_modified(event): - if event.src_path != block_meta_db: - return - self.refresh_db() - if auto_refresh: - def auto_refresher(): - observer = Observer() - observer.schedule( - Refresher(), identify_home(), recursive=False) - observer.start() - while observer.is_alive(): - # call import func with timeout - observer.join(120) - Thread(target=auto_refresher, daemon=True).start() - - def get(self): - return self.block_list - - def refresh_db(self): - self.check_time = get_epoch() - if not self.block_type: - self.block_list = get_block_list() - else: - self.block_list = get_blocks_by_type(self.block_type) diff --git a/src/onionrblocks/blockmetadata/__init__.py b/src/onionrblocks/blockmetadata/__init__.py deleted file mode 100644 index 29d3dc01..00000000 --- a/src/onionrblocks/blockmetadata/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -''' - Onionr - Private P2P Communication - - Module to work with block metadata -''' -''' - 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 . -''' - -from . import hasblock, fromdata, process -has_block = hasblock.has_block -process_block_metadata = process.process_block_metadata -get_block_metadata_from_data = fromdata.get_block_metadata_from_data diff --git a/src/onionrblocks/blockmetadata/fromdata.py b/src/onionrblocks/blockmetadata/fromdata.py deleted file mode 100644 index 6c98b282..00000000 --- a/src/onionrblocks/blockmetadata/fromdata.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Onionr - Private P2P Communication. - - Return a useful tuple of (metadata (header), meta, and data) by accepting raw block data -""" -from json import JSONDecodeError -import ujson as json - -from onionrutils import bytesconverter -import logger -""" - 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 . -""" - - -def get_block_metadata_from_data(block_data): - """ - accepts block contents as string, returns a tuple of - metadata, meta (meta being internal metadata, which will be - returned as an encrypted base64 string if it is encrypted, dict if not). - """ - meta = {} - metadata = {} - data = block_data - try: - block_data = block_data.encode() - except AttributeError: - pass - - try: - metadata = json.loads(bytesconverter.bytes_to_str(block_data[:block_data.find(b'\n')])) - except JSONDecodeError: - pass - except ValueError: - logger.warn("Could not get metadata from:", terminal=True) - logger.warn(block_data, terminal=True) - else: - data = block_data[block_data.find(b'\n'):] - - meta = metadata['meta'] - return (metadata, meta, data) diff --git a/src/onionrblocks/blockmetadata/hasblock.py b/src/onionrblocks/blockmetadata/hasblock.py deleted file mode 100644 index 72b6d6eb..00000000 --- a/src/onionrblocks/blockmetadata/hasblock.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Onionr - Private P2P Communication. - -Return a bool if a block is in the block metadata db or not -""" -import sqlite3 -from coredb import dbfiles -import onionrexceptions -from onionrutils import stringvalidators -from etc import onionrvalues -""" - 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 . -""" - - -def has_block(hash: str) -> bool: - """Check for new block in the block meta db.""" - conn = sqlite3.connect( - dbfiles.block_meta_db, - timeout=onionrvalues.DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - if not stringvalidators.validate_hash(hash): - raise onionrexceptions.InvalidHexHash("Invalid hash") - for result in c.execute("SELECT COUNT() FROM hashes WHERE hash = ?", (hash,)): - if result[0] >= 1: - conn.commit() - conn.close() - return True - else: - conn.commit() - conn.close() - return False - return False diff --git a/src/onionrblocks/blockmetadata/process.py b/src/onionrblocks/blockmetadata/process.py deleted file mode 100644 index fe094977..00000000 --- a/src/onionrblocks/blockmetadata/process.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Onionr - Private P2P Communication. - -Process block metadata with relevant actions -""" -from etc import onionrvalues -from onionrblocks import onionrblockapi -from onionrutils import epoch, bytesconverter -from coredb import blockmetadb -import logger -from onionrplugins import onionrevents -import onionrexceptions -from onionrusers import onionrusers -from onionrutils import updater -""" - 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 . -""" - - -def process_block_metadata(blockHash: str): - """ - Read metadata from a block and cache it to the block database. - - blockHash -> sha3_256 hex formatted hash of Onionr block - """ - curTime = epoch.get_rounded_epoch(roundS=60) - myBlock = onionrblockapi.Block(blockHash) - if myBlock.isEncrypted: - myBlock.decrypt() - if (myBlock.isEncrypted and myBlock.decrypted) or (not myBlock.isEncrypted): - blockType = myBlock.getMetadata('type') # we would use myBlock.getType() here, but it is bugged with encrypted blocks - - signer = bytesconverter.bytes_to_str(myBlock.signer) - valid = myBlock.verifySig() - if valid: - if myBlock.getMetadata('newFSKey') is not None: - try: - onionrusers.OnionrUser(signer).addForwardKey(myBlock.getMetadata('newFSKey')) - except onionrexceptions.InvalidPubkey: - logger.warn('%s has invalid forward secrecy key to add: %s' % (signer, myBlock.getMetadata('newFSKey'))) - - try: - if len(blockType) <= onionrvalues.MAX_BLOCK_TYPE_LENGTH: - blockmetadb.update_block_info(blockHash, 'dataType', blockType) - except TypeError: - logger.warn("Missing block information") - pass - # Set block expire time if specified - try: - expireTime = int(myBlock.getHeader('expire')) - # test that expire time is an integer of sane length (for epoch) - # doesn't matter if its too large because of the min() func below - if not len(str(expireTime)) < 20: raise ValueError('timestamp invalid') - except (ValueError, TypeError) as e: - expireTime = onionrvalues.DEFAULT_EXPIRE + curTime - finally: - expireTime = min(expireTime, curTime + onionrvalues.DEFAULT_EXPIRE) - blockmetadb.update_block_info(blockHash, 'expire', expireTime) - - if blockType == 'update': updater.update_event(myBlock) - onionrevents.event('processblocks', data = {'block': myBlock, 'type': blockType, 'signer': signer, 'validSig': valid}) diff --git a/src/onionrblocks/deleteplaintext.py b/src/onionrblocks/deleteplaintext.py deleted file mode 100644 index 427283be..00000000 --- a/src/onionrblocks/deleteplaintext.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Onionr - P2P Anonymous Storage Network. - -Delete but do not blacklist plaintext blocks -""" -from coredb import blockmetadb -from onionrstorage.removeblock import remove_block -import onionrstorage -from .onionrblockapi import Block -import onionrexceptions -""" - 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 . -""" - - -def delete_plaintext_no_blacklist(): - """Delete, but do not blacklist, plaintext blocks.""" - - block_list = blockmetadb.get_block_list() - - for block in block_list: - block = Block(hash=block, decrypt=False) - if not block.isEncrypted: - remove_block(block.hash) # delete metadata entry - onionrstorage.deleteBlock(block.hash) # delete block data diff --git a/src/onionrblocks/insert/__init__.py b/src/onionrblocks/insert/__init__.py deleted file mode 100644 index e516f6b6..00000000 --- a/src/onionrblocks/insert/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from . import main, timeinsert - -insert_block = main.insert_block -time_insert = timeinsert.time_insert \ No newline at end of file diff --git a/src/onionrblocks/insert/main.py b/src/onionrblocks/insert/main.py deleted file mode 100644 index 77acf276..00000000 --- a/src/onionrblocks/insert/main.py +++ /dev/null @@ -1,267 +0,0 @@ -"""Onionr - Private P2P Communication. - -Create and insert Onionr blocks -""" -from typing import Union -import ujson as json - -from gevent import spawn - -from onionrutils import bytesconverter, epoch -import filepaths -import onionrstorage -from .. import storagecounter -from onionrplugins import onionrevents as events -from etc import onionrvalues -import config -import onionrcrypto as crypto -import onionrexceptions -from onionrusers import onionrusers -from onionrutils import localcommand, stringvalidators -from .. import blockmetadata -import coredb -from onionrproofs import subprocesspow -import logger -from onionrtypes import UserIDSecretKey -""" - 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 . -""" -storage_counter = storagecounter.StorageCounter() - - -def _check_upload_queue(): - """ - Return the current upload queue len. - - raises OverflowError if max, false if api not running - """ - max_upload_queue: int = 5000 - queue = localcommand.local_command('/gethidden', max_wait=10) - up_queue = False - - try: - up_queue = len(queue.splitlines()) - except AttributeError: - pass - else: - if up_queue >= max_upload_queue: - raise OverflowError - return up_queue - - -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, - signing_key: UserIDSecretKey = '') -> Union[str, bool]: - """ - Create and insert a block into the network. - - encryptType must be specified to encrypt a block - if expire is less than date, assumes seconds into future. - if not assume exact epoch - """ - our_private_key = crypto.priv_key - our_pub_key = crypto.pub_key - - allocationReachedMessage = 'Cannot insert block, disk allocation reached.' - if storage_counter.is_full(): - logger.error(allocationReachedMessage) - raise onionrexceptions.DiskAllocationReached - - if signing_key != '': - # if it was specified to use an alternative private key - our_private_key = signing_key - our_pub_key = bytesconverter.bytes_to_str( - crypto.cryptoutils.get_pub_key_from_priv(our_private_key)) - - retData = False - - if type(data) is None: - raise ValueError('Data cannot be none') - - createTime = epoch.get_epoch() - - dataNonce = bytesconverter.bytes_to_str(crypto.hashers.sha3_hash(data)) - try: - with open(filepaths.data_nonce_file, 'r') as nonces: - if dataNonce in nonces: - return retData - except FileNotFoundError: - pass - # record nonce - with open(filepaths.data_nonce_file, 'a') as nonce_file: - nonce_file.write(dataNonce + '\n') - - plaintext = data - plaintextMeta = {} - plaintextPeer = asymPeer - - retData = '' - signature = '' - signer = '' - metadata = {} - - # metadata is full block metadata - # meta is internal, user specified metadata - - # only use header if not set in provided meta - - meta['type'] = str(header) - - if encryptType in ('asym', 'sym'): - metadata['encryptType'] = encryptType - else: - if not config.get('general.store_plaintext_blocks', True): - raise onionrexceptions.InvalidMetadata( - "Plaintext blocks are disabled, " + - "yet a plaintext block was being inserted") - if encryptType not in ('', None): - raise onionrexceptions.InvalidMetadata( - 'encryptType must be asym or sym, or blank') - - try: - data = data.encode() - except AttributeError: - pass - - if encryptType == 'asym': - # Duplicate the time in encrypted messages to help prevent replays - meta['rply'] = createTime - if sign and asymPeer != our_pub_key: - try: - forwardEncrypted = onionrusers.OnionrUser( - asymPeer).forwardEncrypt(data) - data = forwardEncrypted[0] - meta['forwardEnc'] = True - # Expire time of key. no sense keeping block after that - expire = forwardEncrypted[2] - except onionrexceptions.InvalidPubkey: - pass - if not disableForward: - fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey() - meta['newFSKey'] = fsKey - jsonMeta = json.dumps(meta) - plaintextMeta = jsonMeta - if sign: - 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') - - # encrypt block metadata/sig/content - if encryptType == 'sym': - raise NotImplementedError("not yet implemented") - elif encryptType == 'asym': - if stringvalidators.validate_pub_key(asymPeer): - # Encrypt block data with forward secrecy key first, but not meta - jsonMeta = json.dumps(meta) - jsonMeta = crypto.encryption.pub_key_encrypt( - jsonMeta, asymPeer, encodedData=True).decode() - data = crypto.encryption.pub_key_encrypt( - data, asymPeer, encodedData=False) - signature = crypto.encryption.pub_key_encrypt( - signature, asymPeer, encodedData=True).decode() - signer = crypto.encryption.pub_key_encrypt( - signer, asymPeer, encodedData=True).decode() - try: - onionrusers.OnionrUser(asymPeer, saveUser=True) - except ValueError: - # if peer is already known - pass - else: - logger.warn(f"{asymPeer} is not a valid key to make a block to") - raise onionrexceptions.InvalidPubkey( - 'tried to make block to invalid key is not a valid base32 encoded ed25519 key') - - # compile metadata - metadata['meta'] = jsonMeta - if len(signature) > 0: # I don't like not pattern - metadata['sig'] = signature - metadata['signer'] = signer - metadata['time'] = createTime - - # ensure expire is integer and of sane length - if type(expire) is not type(None): # noqa - if not len(str(int(expire))) < 20: - raise ValueError( - 'expire must be valid int less than 20 digits in length') - # if expire is less than date, assume seconds into future - if expire < epoch.get_epoch(): - expire = epoch.get_epoch() + expire - metadata['expire'] = expire - - # send block data (and metadata) to POW module to get tokenized block data - payload = subprocesspow.SubprocessPOW(data, metadata).start() - - if payload != False: # noqa - try: - retData = onionrstorage.set_data(payload) - except onionrexceptions.DiskAllocationReached: - logger.error(allocationReachedMessage) - retData = False - else: - if disableForward: - logger.warn( - f'{retData} asym encrypted block created w/o ephemerality') - """ - Tell the api server through localCommand to wait for the daemon to - upload this block to make statistical analysis more difficult - """ - spawn( - localcommand.local_command, - '/daemon-event/upload_event', - post=True, - is_json=True, - post_data={'block': retData} - ).get(timeout=5) - coredb.blockmetadb.add.add_to_block_DB( - retData, selfInsert=True, dataSaved=True) - - if expire is None: - coredb.blockmetadb.update_block_info( - retData, 'expire', - createTime + onionrvalues.DEFAULT_EXPIRE) - else: - coredb.blockmetadb.update_block_info(retData, 'expire', expire) - - blockmetadata.process_block_metadata(retData) - - if retData != False: # noqa - if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS: - events.event('insertdeniable', - {'content': plaintext, 'meta': plaintextMeta, - 'hash': retData, - 'peer': bytesconverter.bytes_to_str(asymPeer)}, - threaded=True) - else: - events.event('insertblock', - {'content': plaintext, 'meta': plaintextMeta, - 'hash': retData, - 'peer': bytesconverter.bytes_to_str(asymPeer)}, - threaded=True) - - spawn( - localcommand.local_command, - '/daemon-event/remove_from_insert_queue_wrapper', - post=True, - post_data={'block_hash': - bytesconverter.bytes_to_str( - crypto.hashers.sha3_hash(data))}, - is_json=True - ).get(timeout=5) - return retData diff --git a/src/onionrblocks/insert/timeinsert.py b/src/onionrblocks/insert/timeinsert.py deleted file mode 100644 index 41d8fcaa..00000000 --- a/src/onionrblocks/insert/timeinsert.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Onionr - Private P2P Communication. - -Wrapper to insert blocks with variable delay -""" -from . import main -""" - 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 . -""" - - -def time_insert(*args, **kwargs): - """Block insert wrapper to allow for insertions independent of mixmate. - - Takes exact args as insert_block, with additional keyword: - delay=n; where n=seconds to tell initial nodes to delay share for. - - defaults to 0 or previously set value in current block meta - """ - try: - kwargs['meta'] - except KeyError: - kwargs['meta'] = {} - - try: - delay = int(kwargs['meta']['dly']) - except KeyError: - delay = 0 - try: - delay = kwargs['delay'] - del kwargs['delay'] - except KeyError: - delay = 0 - - # Ensure delay >=0 - if delay < 0: - raise ValueError('delay cannot be less than 0') - - kwargs['meta']['dly'] = delay - - return main.insert_block(*args, **kwargs) diff --git a/src/onionrblocks/onionrblacklist.py b/src/onionrblocks/onionrblacklist.py deleted file mode 100755 index 673e9a62..00000000 --- a/src/onionrblocks/onionrblacklist.py +++ /dev/null @@ -1,130 +0,0 @@ -"""Onionr - Private P2P Communication. - -Handle maintenance of a blacklist database, for blocks and peers -""" -import sqlite3 -import os - -from onionrplugins.onionrevents import event -import onionrcrypto -from onionrutils import epoch, bytesconverter -from coredb import dbfiles -from etc.onionrvalues import DATABASE_LOCK_TIMEOUT -""" - 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 . -""" - - -class OnionrBlackList: - def __init__(self): - self.blacklistDB = dbfiles.blacklist_db - - if not os.path.exists(dbfiles.blacklist_db): - self.generateDB() - return - - def inBlacklist(self, data): - hashed = bytesconverter.bytes_to_str( - onionrcrypto.hashers.sha3_hash(data)) - retData = False - - if not hashed.isalnum(): - raise Exception("Hashed data is not alpha numeric") - if len(hashed) > 64: - raise Exception("Hashed data is too large") - - for i in self._dbExecute( - "SELECT * FROM blacklist WHERE hash = ?", (hashed,)): - # this only executes if an entry is present by that hash - retData = True - break - - return retData - - def _dbExecute(self, toExec, params=()): - conn = sqlite3.connect(self.blacklistDB, timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - retData = c.execute(toExec, params) - conn.commit() - return retData - - def deleteBeforeDate(self, date): - # TODO, delete blacklist entries before date - return - - def deleteExpired(self, dataType=0): - """Delete expired entries""" - deleteList = [] - curTime = epoch.get_epoch() - - try: - int(dataType) - except AttributeError: - raise TypeError("dataType must be int") - - for i in self._dbExecute( - 'SELECT * FROM blacklist WHERE dataType = ?', (dataType,)): - if i[1] == dataType: - if (curTime - i[2]) >= i[3]: - deleteList.append(i[0]) - - for thing in deleteList: - self._dbExecute("DELETE FROM blacklist WHERE hash = ?", (thing,)) - - def generateDB(self): - return - - def clearDB(self): - self._dbExecute("""DELETE FROM blacklist;""") - - def getList(self): - data = self._dbExecute('SELECT * FROM blacklist') - myList = [] - for i in data: - myList.append(i[0]) - return myList - - def addToDB(self, data, dataType=0, expire=0): - """Add to the blacklist. Intended to be block hash, block data, peers, or transport addresses - 0=block - 1=peer - 2=pubkey - """ - - # we hash the data so we can remove data entirely from our node's disk - hashed = bytesconverter.bytes_to_str(onionrcrypto.hashers.sha3_hash(data)) - - event('blacklist_add', data={'data': data, 'hash': hashed}) - - if len(hashed) > 64: - raise Exception("Hashed data is too large") - - if not hashed.isalnum(): - raise Exception("Hashed data is not alpha numeric") - try: - int(dataType) - except ValueError: - raise Exception("dataType is not int") - try: - int(expire) - except ValueError: - raise Exception("expire is not int") - if self.inBlacklist(hashed): - return - insert = (hashed,) - blacklistDate = epoch.get_epoch() - try: - self._dbExecute("INSERT INTO blacklist (hash, dataType, blacklistDate, expire) VALUES(?, ?, ?, ?);", (str(hashed), dataType, blacklistDate, expire)) - except sqlite3.IntegrityError: - pass diff --git a/src/onionrblocks/onionrblockapi.py b/src/onionrblocks/onionrblockapi.py deleted file mode 100755 index 875d8faf..00000000 --- a/src/onionrblocks/onionrblockapi.py +++ /dev/null @@ -1,443 +0,0 @@ -"""Onionr - P2P Anonymous Storage Network. - -OnionrBlocks class for abstraction of blocks -""" -import datetime -import onionrstorage - -import unpaddedbase32 -import ujson as json -import nacl.exceptions - -import logger -import onionrexceptions -from onionrusers import onionrusers -from onionrutils import stringvalidators, epoch -from coredb import blockmetadb -from onionrutils import bytesconverter -import onionrblocks -from onionrcrypto import encryption, cryptoutils as cryptoutils, signing -""" - 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 . -""" - - -class Block: - blockCacheOrder = list() # NEVER write your own code that writes to this! - blockCache = dict() # should never be accessed directly, look at Block.getCache() - - def __init__(self, hash = None, type = None, content = None, expire=None, decrypt=False, bypassReplayCheck=False): - # take from arguments - # sometimes people input a bytes object instead of str in `hash` - if (not hash is None) and isinstance(hash, bytes): - hash = hash.decode() - - self.hash = hash - self.btype = type - self.bcontent = content - self.expire = expire - self.bypassReplayCheck = bypassReplayCheck - - # initialize variables - self.valid = True - self.raw = None - self.signed = False - self.signature = None - self.signedData = None - self.blockFile = None - self.bheader = {} - self.bmetadata = {} - self.isEncrypted = False - self.decrypted = False - self.signer = None - self.validSig = False - self.autoDecrypt = decrypt - self.claimedTime = None - - self.update() - - def decrypt(self, encodedData = True): - """ - Decrypt a block, loading decrypted data into their vars - """ - - if self.decrypted: - return True - retData = False - # decrypt data - if self.getHeader('encryptType') == 'asym': - try: - self.bcontent = encryption.pub_key_decrypt(self.bcontent, encodedData=False) - - bmeta = encryption.pub_key_decrypt(self.bmetadata, encodedData=encodedData) - - try: - bmeta = bmeta.decode() - except AttributeError: - # yet another bytes fix - pass - self.bmetadata = json.loads(bmeta) - self.signature = encryption.pub_key_decrypt(self.signature, encodedData=encodedData) - - self.signer = encryption.pub_key_decrypt(self.signer, encodedData=encodedData) - - self.bheader['signer'] = self.signer.decode() - self.signedData = json.dumps(self.bmetadata).encode() + self.bcontent - - if not self.signer is None: - if not self.verifySig(): - raise onionrexceptions.SignatureError("Block has invalid signature") - - # 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 - except (AssertionError, KeyError, TypeError, onionrexceptions.ReplayAttack) as e: - if not self.bypassReplayCheck: - # Zero out variables to prevent reading of replays - self.bmetadata = {} - self.signer = '' - self.bheader['signer'] = '' - self.signedData = '' - self.signature = '' - raise onionrexceptions.ReplayAttack('Signature is too old. possible replay attack') - try: - if not self.bmetadata['forwardEnc']: raise KeyError - except (AssertionError, KeyError) as e: - pass - else: - try: - self.bcontent = onionrusers.OnionrUser(self.signer).forwardDecrypt(self.bcontent) - except (onionrexceptions.DecryptionError, nacl.exceptions.CryptoError) as e: - logger.error(str(e)) - pass - except (nacl.exceptions.CryptoError,) as e: - logger.debug(f'Could not decrypt block. encodedData: {encodedData}. Either invalid key or corrupted data ' + str(e)) - except onionrexceptions.ReplayAttack: - logger.warn('%s is possibly a replay attack' % (self.hash,)) - else: - retData = True - self.decrypted = True - return retData - - def verifySig(self): - """ - Verify if a block's signature is signed by its claimed signer - """ - 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 - return self.validSig - - def update(self, data = None, file = None): - """ - Loads data from a block in to the current object. - - Inputs: - - data (str): - - if None: will load from file by hash - - else: will load from `data` string - - file (str): - - if None: will load from file specified in this parameter - - else: will load from wherever block is stored by hash - - Outputs: - - (bool): indicates whether or not the operation was successful - """ - try: - # import from string - blockdata = data - - # import from file - if blockdata is None: - try: - blockdata = onionrstorage.getData(self.getHash())#.decode() - except AttributeError: - raise onionrexceptions.NoDataAvailable('Block does not exist') - else: - self.blockFile = None - # parse block - self.raw = blockdata - self.bheader = json.loads(self.getRaw()[:self.getRaw().index(b'\n')]) - self.bcontent = self.getRaw()[self.getRaw().index(b'\n') + 1:] - if ('encryptType' in self.bheader) and (self.bheader['encryptType'] in ('asym', 'sym')): - self.bmetadata = self.getHeader('meta', None) - self.isEncrypted = True - else: - self.bmetadata = json.loads(self.getHeader('meta', None)) - self.btype = self.getMetadata('type', None) - self.signed = ('sig' in self.getHeader() and self.getHeader('sig') != '') - # TODO: detect if signer is hash of pubkey or not - 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').encode() + self.getContent()) - self.date = blockmetadb.get_block_date(self.getHash()) - self.claimedTime = self.getHeader('time', None) - - if not self.getDate() is None: - self.date = datetime.datetime.fromtimestamp(self.getDate()) - - self.valid = True - - if self.autoDecrypt: - self.decrypt() - - return True - except Exception as e: - logger.warn('Failed to parse block %s' % self.getHash(), error = e, timestamp = False) - - - self.valid = False - return False - - - # getters - - def getExpire(self): - """ - Returns the expire time for a block - - Outputs: - - (int): the expire time for a block, or None - """ - return self.expire - - def getHash(self): - """ - Returns the hash of the block if saved to file - - Outputs: - - (str): the hash of the block, or None - """ - - return self.hash - - def getType(self): - """ - Returns the type of the block - - Outputs: - - (str): the type of the block - """ - return self.btype - - def getRaw(self): - """ - Returns the raw contents of the block, if saved to file - - Outputs: - - (bytes): the raw contents of the block, or None - """ - - return self.raw - - def getHeader(self, key = None, default = None): - """ - Returns the header information - - Inputs: - - key (str): only returns the value of the key in the header - - Outputs: - - (dict/str): either the whole header as a dict, or one value - """ - - if not key is None: - if key in self.getHeader(): - return self.getHeader()[key] - return default - return self.bheader - - def getMetadata(self, key = None, default = None): - """ - Returns the metadata information - - Inputs: - - key (str): only returns the value of the key in the metadata - - Outputs: - - (dict/str): either the whole metadata as a dict, or one value - """ - - if not key is None: - if key in self.getMetadata(): - return self.getMetadata()[key] - return default - return self.bmetadata - - def getContent(self): - """ - Returns the contents of the block - - Outputs: - - (str): the contents of the block - """ - - return self.bcontent - - def getDate(self): - """ - Returns the date that the block was received, if loaded from file - - Outputs: - - (datetime): the date that the block was received - """ - - return self.date - - def getBlockFile(self): - """ - Returns the location of the block file if it is saved - - Outputs: - - (str): the location of the block file, or None - """ - - return self.blockFile - - def isValid(self): - """ - Checks if the block is valid - - Outputs: - - (bool): whether or not the block is valid - """ - - return self.valid - - def isSigned(self): - """ - Checks if the block was signed - - Outputs: - - (bool): whether or not the block is signed - """ - - return self.signed - - def getSignature(self): - """ - Returns the base64-encoded signature - - Outputs: - - (str): the signature, or None - """ - - return self.signature - - def getSignedData(self): - """ - Returns the data that was signed - - Outputs: - - (str): the data that was signed, or None - """ - - return self.signedData - - def isSigner(self, signer, encodedData = True): - """ - Checks if the block was signed by the signer inputted - - Inputs: - - signer (str): the public key of the signer to check against - - encodedData (bool): whether or not the `signer` argument is base64 encoded - - 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 - - return bool(signing.ed_verify(self.getSignedData(), signer, self.getSignature(), encodedData = encodedData)) - except: - return False - - # setters - - def setType(self, btype): - """ - Sets the type of the block - - Inputs: - - btype (str): the type of block to be set to - - Outputs: - - (Block): the Block instance - """ - - self.btype = btype - return self - - def setMetadata(self, key, val): - """ - Sets a custom metadata value - - Metadata should not store block-specific data structures. - - Inputs: - - key (str): the key - - val: the value (type is irrelevant) - - Outputs: - - (Block): the Block instance - """ - - self.bmetadata[key] = val - return self - - def setContent(self, bcontent): - """ - Sets the contents of the block - - Inputs: - - bcontent (str): the contents to be set to - - Outputs: - - (Block): the Block instance - """ - - self.bcontent = str(bcontent) - return self - - # static functions - def exists(bHash): - """ - Checks if a block is saved to file or not - - Inputs: - - hash (str/Block): - - if (Block): check if this block is saved to file - - if (str): check if a block by this hash is in file - - Outputs: - - (bool): whether or not the block file exists - """ - - # no input data? scrap it. - if bHash is None: - return False - - if isinstance(bHash, Block): - bHash = bHash.getHash() - - ret = isinstance(onionrstorage.getData(bHash), type(None)) - - return not ret diff --git a/src/onionrblocks/storagecounter.py b/src/onionrblocks/storagecounter.py deleted file mode 100755 index 7ff0fe9a..00000000 --- a/src/onionrblocks/storagecounter.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Onionr - Private P2P Communication. - -Keep track of how much disk space we're using -""" -from pathlib import Path - -from threading import Thread - -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -import config -from filepaths import usage_file -""" - 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 . -""" -config.reload() - - -def _read_data_file(f) -> int: - amount = 0 - try: - with open(f, 'r') as f: - amount = int(f.read()) - except FileNotFoundError: - pass - except ValueError: - pass # Possibly happens when the file is empty - return amount - - -class StorageCounter: - def __init__(self): - self.data_file = usage_file - self.amount: int = None - Path(self.data_file).touch() - - def auto_refresher(): - class Refresher(FileSystemEventHandler): - @staticmethod - def on_modified(event): - self.amount = _read_data_file(self.data_file) - observer = Observer() - observer.schedule(Refresher(), usage_file) - observer.start() - while observer.is_alive(): - # call import func with timeout - observer.join(120) - Thread(target=auto_refresher, daemon=True).start() - self.amount = _read_data_file(self.data_file) - - def is_full(self) -> bool: - """Returns if the allocated disk space is full (this is Onionr config, - not true FS capacity)""" - ret_data = False - if config.get('allocations.disk', 1073741824) <= (self.amount + 1000): - ret_data = True - return ret_data - - def _update(self, data): - with open(self.data_file, 'w') as data_file: - data_file.write(str(data)) - - def get_percent(self) -> int: - """Return percent (decimal/float) of disk space we're using""" - amount = self.amount - return round(amount / config.get('allocations.disk', 2000000000), 2) - - def add_bytes(self, amount) -> int: - """Record that we are now using more disk space, - unless doing so would exceed configured max""" - new_amount = amount + self.amount - ret_data = new_amount - if new_amount > config.get('allocations.disk', 2000000000): - ret_data = 0 - else: - self._update(new_amount) - return ret_data - - def remove_bytes(self, amount) -> int: - """Record that we are now using less disk space""" - new_amount = self.amount - amount - self._update(new_amount) - return new_amount diff --git a/src/onionrcommands/banblocks.py b/src/onionrcommands/banblocks.py deleted file mode 100755 index 49fa21f8..00000000 --- a/src/onionrcommands/banblocks.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Onionr - Private P2P Communication. - -This file contains the command for banning blocks from the node -""" -import sys -import logger -from onionrutils import stringvalidators -from onionrstorage import removeblock -from onionrstorage import deleteBlock -from onionrblocks import onionrblacklist -from utils import reconstructhash -""" - 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 . -""" - - -def ban_block(): - """Delete a block, permanently blacklisting it.""" - blacklist = onionrblacklist.OnionrBlackList() - try: - ban = sys.argv[2] - except IndexError: - # Get the hash if its not provided as a CLI argument - ban = logger.readline('Enter a block hash:').strip() - # Make sure the hash has no truncated zeroes - ban = reconstructhash.reconstruct_hash(ban) - if stringvalidators.validate_hash(ban): - if not blacklist.inBlacklist(ban): - try: - blacklist.addToDB(ban) - removeblock.remove_block(ban) - deleteBlock(ban) - except Exception as error: # pylint: disable=W0703 - logger.error('Could not blacklist block', - error=error, terminal=True) - else: - logger.info('Block blacklisted', terminal=True) - else: - logger.warn('That block is already blacklisted', terminal=True) - else: - logger.error('Invalid block hash', terminal=True) - - -ban_block.onionr_help = ": " # type: ignore -ban_block.onionr_help += "deletes and blacklists a block" # type: ignore diff --git a/src/onionrcommands/daemonlaunch/__init__.py b/src/onionrcommands/daemonlaunch/__init__.py index d54c7452..1fad7b89 100755 --- a/src/onionrcommands/daemonlaunch/__init__.py +++ b/src/onionrcommands/daemonlaunch/__init__.py @@ -35,7 +35,6 @@ from utils.bettersleep import better_sleep from .killdaemon import kill_daemon # noqa from .showlogo import show_logo -from sneakernet import sneakernet_import_thread from setupkvvars import setup_kv """ This program is free software: you can redistribute it and/or modify @@ -142,9 +141,6 @@ def daemon(): events.event('init', threaded=False) events.event('daemon_start') - if config.get('transports.sneakernet', True): - Thread(target=sneakernet_import_thread, daemon=True).start() - better_sleep(5) diff --git a/src/onionrcommands/exportblocks.py b/src/onionrcommands/exportblocks.py deleted file mode 100755 index 404a6f92..00000000 --- a/src/onionrcommands/exportblocks.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Onionr - Private P2P Communication. - -This file handles the command for exporting blocks to disk -""" -import sys - -import logger -import onionrstorage -from utils import createdirs -from onionrutils import stringvalidators -from etc.onionrvalues import BLOCK_EXPORT_FILE_EXT -import filepaths - -import os -from coredb import blockmetadb -""" - 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 . -""" - - -def _do_export(b_hash): - createdirs.create_dirs() - data = onionrstorage.getData(b_hash) - with open('%s/%s%s' % (filepaths.export_location, - b_hash, BLOCK_EXPORT_FILE_EXT), 'wb') as export: - export.write(data) - logger.info('Block exported as file', terminal=True) - - -def export_block(*args): - """Export block based on hash from stdin or argv.""" - if args: - b_hash = args[0] - else: - try: - if not stringvalidators.validate_hash(sys.argv[2]): - raise ValueError - except (IndexError, ValueError): - logger.error('No valid block hash specified.', terminal=True) - sys.exit(1) - else: - b_hash = sys.argv[2] - _do_export(b_hash) - - -export_block.onionr_help = ": Export block to " # type: ignore -export_block.onionr_help += "a file. Export directory is in " # type: ignore -export_block.onionr_help += "Onionr home under block-export" # type: ignore diff --git a/src/onionrcommands/filecommands.py b/src/onionrcommands/filecommands.py deleted file mode 100755 index 315441df..00000000 --- a/src/onionrcommands/filecommands.py +++ /dev/null @@ -1,106 +0,0 @@ -"""Onionr - Private P2P Communication. - -This file handles the commands for adding -and getting files from the Onionr network -""" -import sys -import os -import logger -from onionrblocks.onionrblockapi import Block -import onionrexceptions -from onionrutils import stringvalidators -from etc import onionrvalues -from onionrblocks import insert -""" - 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 . -""" - -_ORIG_DIR = onionrvalues.ORIG_RUN_DIR_ENV_VAR - - -def _get_dir(path: str) -> str: - if not os.getenv(_ORIG_DIR) is None: - return os.getenv(_ORIG_DIR) + '/' + path # type: ignore - else: - return path - - -def add_html(singleBlock=True, blockType='html'): - """Create one-off web page from HTML file, no ext resources.""" - add_file(blockType=blockType) - - -add_html.onionr_help = "Adds an HTML file into Onionr. Does " # type: ignore -add_html.onionr_help += "not include dependant resources" # type: ignore - - -def add_file(blockType='bin'): - """Add a file to the onionr network.""" - if len(sys.argv) >= 3: - filename = sys.argv[2] - - if not os.path.exists(_get_dir(filename)): - logger.error( - 'That file does not exist. Improper path (specify full path)?', - terminal=True) - return - logger.info('Adding file, this might take a long time.', - terminal=True) - try: - with open(_get_dir(filename), 'rb') as single_file: - blockhash = insert(single_file.read(), header=blockType) - if len(blockhash) > 0: - logger.info('File %s saved in block %s' % - (filename, blockhash), terminal=True) - except Exception as err: # pylint: disable=W0703 - logger.error('Failed to save file in block ' + - str(err), timestamp=False, terminal=True) - else: - logger.error('%s add-file ' % - sys.argv[0], timestamp=False, terminal=True) - - -add_file.onionr_help = " Add a file into " # type: ignore -add_file.onionr_help += "the Onionr network" # type: ignore - - -def get_file(): - """Get a file from onionr blocks.""" - try: - file_name = _get_dir(sys.argv[2]) - bHash = sys.argv[3] - except IndexError: - logger.error("Syntax %s %s" % ( - sys.argv[0], '/path/to/filename '), terminal=True) - else: - logger.info(file_name, terminal=True) - - if os.path.exists(file_name): - logger.error("File already exists", terminal=True) - return - if not stringvalidators.validate_hash(bHash): - logger.error('Block hash is invalid', terminal=True) - return - - try: - with open(file_name, 'wb') as my_file: - my_file.write(Block(bHash).bcontent) - except onionrexceptions.NoDataAvailable: - logger.error( - 'That block is not available. Trying again later may work.', - terminal=True) - - -get_file.onionr_help = " : Download " # type: ignore -get_file.onionr_help += "a file from the onionr network." # type: ignore diff --git a/src/onionrcommands/listsites.py b/src/onionrcommands/listsites.py deleted file mode 100644 index 3f874cfe..00000000 --- a/src/onionrcommands/listsites.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Onionr - Private P2P Communication. - -Dumb listing of Onionr sites -""" -from coredb.blockmetadb import get_blocks_by_type -from onionrblocks.onionrblockapi import Block -import logger -""" - 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 . -""" - - -def print_site_list(): - """Create a new MOTD message for the Onionr network.""" - block_list = get_blocks_by_type('osite') - if not block_list: - logger.info('No sites saved right now', terminal=True) - for block in block_list: - block = Block(block) - if block.isSigned(): - logger.info(block.signer.replace('=', ''), terminal=True) - else: - logger.info(block.hash, terminal=True) - - -print_site_list.onionr_help = "Dumbly list all Onionr sites currently saved" # type: ignore diff --git a/src/onionrcommands/onionrstatistics.py b/src/onionrcommands/onionrstatistics.py index 6502e86c..fd54146a 100755 --- a/src/onionrcommands/onionrstatistics.py +++ b/src/onionrcommands/onionrstatistics.py @@ -4,10 +4,9 @@ This module defines commands to show stats/details about the local node """ import os import logger -from onionrblocks import onionrblacklist from onionrutils import mnemonickeys from utils import sizeutils, getconsolewidth, identifyhome -from coredb import blockmetadb, keydb +from coredb import keydb import onionrcrypto import config from etc import onionrvalues @@ -43,9 +42,8 @@ def show_stats(): """Print/log statistic info about our Onionr install.""" try: # define stats messages here - totalBlocks = len(blockmetadb.get_block_list()) home = identifyhome.identify_home() - totalBanned = len(onionrblacklist.OnionrBlackList().getList()) + messages = { # info about local client @@ -69,9 +67,7 @@ def show_stats(): 'div2': True, 'Enabled Plugins': str(len(config.get('plugins.enabled', list()))) + ' / ' + - str(len(os.listdir(home + 'plugins/'))), - 'Stored Blocks': str(totalBlocks), - 'Deleted Blocks': str(totalBanned) + str(len(os.listdir(home + 'plugins/'))) } # color configuration diff --git a/src/onionrcommands/parser/arguments.py b/src/onionrcommands/parser/arguments.py index d2669004..ad5fa698 100644 --- a/src/onionrcommands/parser/arguments.py +++ b/src/onionrcommands/parser/arguments.py @@ -6,19 +6,14 @@ from typing import Callable from .. import onionrstatistics, version, daemonlaunch from .. import openwebinterface -from .. import banblocks # Command to blacklist a block by its hash -from .. import filecommands # commands to share files with onionr -from .. import exportblocks # commands to export blocks from .. import pubkeymanager # commands to add or change id 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 # cmd to execute the runtime integration tests -from .. import sitecreator # cmd to create multi-page sites -from ..listsites import print_site_list # cmd to list list ids + import onionrexceptions -from onionrutils import importnewblocks # func to import new blocks """ 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 @@ -42,8 +37,6 @@ def get_arguments() -> dict: dynamically modify them with plugins """ args = { - ('blacklist', 'blacklist-block', 'remove-block', - 'removeblock', 'banblock', 'ban-block'): banblocks.ban_block, ('details', 'info'): onionrstatistics.show_details, ('stats', 'statistics'): onionrstatistics.show_stats, ('version',): version.version, @@ -53,15 +46,6 @@ def get_arguments() -> dict: ('openhome', 'gui', 'openweb', 'open-home', 'open-web'): openwebinterface.open_home, ('get-url', 'url', 'get-web'): openwebinterface.get_url, - ('addhtml', 'add-html'): filecommands.add_html, - ('addsite', 'add-site', - 'update-site', 'updatesite'): sitecreator.create_multipage_site, - ('listsites', 'list-sites'): print_site_list, - ('addfile', 'add-file'): filecommands.add_file, - ('get-file', 'getfile'): filecommands.get_file, - ('export-block', 'exportblock'): exportblocks.export_block, - ('importblocks', - 'import-blocks', 'import-block'): importnewblocks.import_new_blocks, ('addid', 'add-id'): pubkeymanager.add_ID, ('changeid', 'change-id'): pubkeymanager.change_ID, ('add-vanity', 'addvanity'): pubkeymanager.add_vanity, diff --git a/src/onionrcommands/sitecreator.py b/src/onionrcommands/sitecreator.py deleted file mode 100644 index 29733105..00000000 --- a/src/onionrcommands/sitecreator.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Onionr - Private P2P Communication. - -Command to create Onionr mutli-page sites -""" -import sys -import os -import getpass - -from niceware import generate_passphrase - -from httpapi import onionrsitesapi -import logger -from etc import onionrvalues -""" - 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 . -""" - - -def create_multipage_site(): - """Command to create mutlipage sites with specified dir and password.""" - error_encountered = False - orig_dir = os.getcwd() - try: - directory = sys.argv[2] - os.chdir(directory) - directory = '.' - except IndexError: - directory = '.' - try: - passphrase = sys.argv[3] - except IndexError: - logger.warn('''It is critical that this passphrase is long. -If you want to update your site later you must remember the passphrase.''', - terminal=True) - - passphrase = "-".join(generate_passphrase(32)) - print("Site restore phrase:", passphrase) - - if len(passphrase) < onionrvalues.PASSWORD_LENGTH: - error_encountered = True - logger.error( - f'Passphrase must be at least {onionrvalues.PASSWORD_LENGTH}' + - ' characters.', terminal=True) - - if error_encountered: - sys.exit(1) - logger.info('Generating site...', terminal=True) - results = onionrsitesapi.sitefiles.create_site( - passphrase, directory=directory) - results = (results[0].replace('=', ''), results[1]) - logger.info(f'Site address {results[0]}', terminal=True) - logger.info(f'Block for this version {results[1]}', terminal=True) - os.chdir(orig_dir) - - -create_multipage_site.onionr_help = "[directory path " # type: ignore -create_multipage_site.onionr_help += "(default relative)] " # type: ignore -create_multipage_site.onionr_help += "- packages a whole " # type: ignore -create_multipage_site.onionr_help += "directory and makes " # type: ignore -create_multipage_site.onionr_help += "it available as " # type: ignore -create_multipage_site.onionr_help += "an Onionr site." # type: ignore diff --git a/src/onionrcrypto/cryptoutils/__init__.py b/src/onionrcrypto/cryptoutils/__init__.py index 0f6251d4..635099d4 100644 --- a/src/onionrcrypto/cryptoutils/__init__.py +++ b/src/onionrcrypto/cryptoutils/__init__.py @@ -1,7 +1,6 @@ -from . import safecompare, replayvalidation, verifypow +from . import safecompare, replayvalidation from . import getpubfrompriv replay_validator = replayvalidation.replay_timestamp_validation safe_compare = safecompare.safe_compare -verify_POW = verifypow.verify_POW get_pub_key_from_priv = getpubfrompriv.get_pub_key_from_priv diff --git a/src/onionrproofs/__init__.py b/src/onionrproofs/__init__.py deleted file mode 100755 index 17730e01..00000000 --- a/src/onionrproofs/__init__.py +++ /dev/null @@ -1,67 +0,0 @@ -"""Onionr - Private P2P Communication. - -Proof of work module -""" -import multiprocessing, time, math, threading, binascii, sys, json -import nacl.encoding, nacl.hash, nacl.utils - -import config -import logger -from onionrblocks import onionrblockapi -from onionrutils import bytesconverter -from onionrcrypto import hashers - -from .blocknoncestart import BLOCK_NONCE_START_INT -from .vdf import create_vdf -""" - 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 . -""" -config.reload() - - -def getDifficultyForNewBlock(data): - """ - Get difficulty for block. Accepts size in integer, Block instance, or str/bytes full block contents - """ - if isinstance(data, onionrblockapi.Block): - dataSizeInBytes = len(bytesconverter.str_to_bytes(data.getRaw())) - else: - dataSizeInBytes = len(bytesconverter.str_to_bytes(data)) - - minDifficulty = config.get('general.minimum_send_pow', 4) - totalDifficulty = max(minDifficulty, math.floor(dataSizeInBytes / 1000000.0)) - - return totalDifficulty - - -def getHashDifficulty(h: str): - """ - Return the amount of leading zeroes in a hex hash string (hexHash) - """ - return len(h) - len(h.lstrip('0')) - - -def hashMeetsDifficulty(hexHash): - """ - Return bool for a hash string to see if it meets pow difficulty defined in config - """ - hashDifficulty = getHashDifficulty(hexHash) - - try: - expected = int(config.get('general.minimum_block_pow')) - except TypeError: - raise ValueError('Missing general.minimum_block_pow config') - - return hashDifficulty >= expected - diff --git a/src/onionrproofs/blocknoncestart.py b/src/onionrproofs/blocknoncestart.py deleted file mode 100644 index 93bf4908..00000000 --- a/src/onionrproofs/blocknoncestart.py +++ /dev/null @@ -1 +0,0 @@ -BLOCK_NONCE_START_INT = -10000000 \ No newline at end of file diff --git a/src/onionrproofs/subprocesspow.py b/src/onionrproofs/subprocesspow.py deleted file mode 100755 index a988b366..00000000 --- a/src/onionrproofs/subprocesspow.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -"""Onionr - Private P2P Communication. - -Multiprocess proof of work -""" - -import os -from multiprocessing import Pipe, Process -import threading -import time -import secrets - -import onionrproofs - -import ujson as json - -import logger -from onionrutils import bytesconverter -from onionrcrypto.hashers import sha3_hash - -""" - 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 . -""" - - -class SubprocessPOW: - def __init__(self, data, metadata, subproc_count=None): - """ - Onionr proof of work using multiple processes - Accepts block data, block metadata - if subproc_count is not set, - os.cpu_count() is used to determine the number of processes - - Due to Python GIL multiprocessing/use of external libraries - is necessary to accelerate CPU bound tasks - """ - # No known benefit to using more processes than there are cores. - # Note: os.cpu_count perhaps not always accurate - if subproc_count is None: - subproc_count = os.cpu_count() - self.subproc_count = subproc_count - self.result = '' - self.shutdown = False - self.data = data - self.metadata = metadata - - """dump dict to measure bytes of json metadata - Cannot reuse later bc the pow token must be added - """ - json_metadata = json.dumps(metadata).encode() - - self.data = bytesconverter.str_to_bytes(data) - - compiled_data = bytes(json_metadata + b'\n' + self.data) - - # Calculate difficulty. May use better algorithm in the future. - self.difficulty = onionrproofs.getDifficultyForNewBlock(compiled_data) - - logger.info('Computing POW (difficulty: %s)...' % (self.difficulty,)) - - self.main_hash = '0' * 64 - self.puzzle = self.main_hash[0:min(self.difficulty, - len(self.main_hash))] - self.shutdown = False - self.payload = None - - def start(self): - """spawn the multiproc handler threads""" - # Create a new thread for each subprocess - for _ in range(self.subproc_count): # noqa - threading.Thread(target=self._spawn_proc, daemon=True).start() - # Monitor the processes for a payload, shut them down when its found - while True: - if self.payload is None: - time.sleep(0.1) - else: - self.shutdown = True - return self.payload - - def _spawn_proc(self): - """Create a child proof of work process - wait for data and send shutdown signal when its found""" - # The importerror started happening in 3.9.x - # not worth fixing because this POW will be replaced by VDF - try: - parent_conn, child_conn = Pipe() - p = Process(target=self.do_pow, args=(child_conn,), daemon=True) - p.start() - except ImportError: - logger.error( - "Error in subprocess module when getting new POW " + - "pipe.\nThis is related to a problem in 3.9.x", terminal=True) - return - payload = None - try: - while True: - data = parent_conn.recv() - if len(data) >= 1: - payload = data - break - except KeyboardInterrupt: - pass - finally: - p.terminate() - self.payload = payload - - def do_pow(self, pipe): - """find partial hash colision generating nonce for a block""" - nonce = 0 - data = self.data - metadata = self.metadata - metadata['n'] = secrets.randbits(16) - puzzle = self.puzzle - difficulty = self.difficulty - try: - while True: - #logger.info('still running', terminal=True) - # Break if shutdown received - try: - if pipe.poll() and pipe.recv() == 'shutdown': - break - except KeyboardInterrupt: - break - # Load nonce into block metadata - metadata['c'] = nonce - # Serialize metadata, combine with block data - payload = json.dumps(metadata).encode() + b'\n' + data - # Check sha3_256 hash of block, compare to puzzle - # Send payload if puzzle finished - token = sha3_hash(payload) - # ensure token is string - token = bytesconverter.bytes_to_str(token) - if puzzle == token[0:difficulty]: - pipe.send(payload) - break - nonce += 1 - except KeyboardInterrupt: - pass diff --git a/src/onionrproofs/vdf.py b/src/onionrproofs/vdf.py deleted file mode 100644 index c48af161..00000000 --- a/src/onionrproofs/vdf.py +++ /dev/null @@ -1,43 +0,0 @@ -import multiprocessing - -import mimcvdf - - -def _wrap_vdf_create(queue, block_data_bytes, rounds): - queue.put(mimcvdf.vdf_create(block_data_bytes, rounds)) - - -def _wrap_vdf_verify(queue, block_data_bytes, block_hash_hex, rounds): - queue.put(mimcvdf.vdf_verify(block_data_bytes, block_hash_hex, rounds)) - - - -def rounds_for_bytes(byte_count: int): - return byte_count * 1000 - - - -def create_vdf(block_data_bytes): - rounds = rounds_for_bytes(block_data_bytes) - queue = multiprocessing.Queue() - vdf_proc = multiprocessing.Process( - target=_wrap_vdf_create, - args=(queue, block_data_bytes, rounds)) - vdf_proc.start() - vdf_proc.join() - return queue.get() - - -def verify_vdf(block_hash_hex, block_data_bytes): - rounds = rounds_for_bytes(block_data_bytes) - if rounds < 10 ** 6: - # >million rounds it starts to take long enough to warrant a subprocess - queue = multiprocessing.Queue() - vdf_proc = multiprocessing.Process( - target=_wrap_vdf_verify, - args=(queue, block_data_bytes, block_hash_hex, rounds)) - vdf_proc.start() - vdf_proc.join() - return queue.get() - return mimcvdf.vdf_verify(block_data_bytes, block_hash_hex, rounds) - diff --git a/src/onionrsetup/dbcreator.py b/src/onionrsetup/dbcreator.py index d9b8e626..1bc6a9d1 100755 --- a/src/onionrsetup/dbcreator.py +++ b/src/onionrsetup/dbcreator.py @@ -77,57 +77,6 @@ def createPeerDB(): conn.close() return -def createBlockDB(): - ''' - Create a database for blocks - - hash - the hash of a block - dateReceived - the date the block was recieved, not necessarily when it was created - decrypted - if we can successfully decrypt the block (does not describe its current state) - dataType - data type of the block - dataFound - if the data has been found for the block - dataSaved - if the data has been saved for the block - sig - optional signature by the author (not optional if author is specified) - author - multi-round partial sha3-256 hash of authors public key - dateClaimed - timestamp claimed inside the block, only as trustworthy as the block author is - expire int - block expire date in epoch - ''' - if os.path.exists(dbfiles.block_meta_db): - raise FileExistsError("Block database already exists") - conn = sqlite3.connect(dbfiles.block_meta_db) - c = conn.cursor() - c.execute('''CREATE TABLE hashes( - hash text not null, - dateReceived int, - decrypted int, - dataType text, - dataFound int, - dataSaved int, - sig text, - author text, - dateClaimed int, - expire int - ); - ''') - conn.commit() - conn.close() - return - -def createBlockDataDB(): - if os.path.exists(dbfiles.block_data_db): - raise FileExistsError("Block data database already exists") - else: - if not os.path.exists(filepaths.block_data_location): - os.mkdir(filepaths.block_data_location) - conn = sqlite3.connect(dbfiles.block_data_db) - c = conn.cursor() - c.execute('''CREATE TABLE blockData( - hash text not null, - data blob not null - ); - ''') - conn.commit() - conn.close() def createForwardKeyDB(): ''' @@ -168,5 +117,4 @@ def create_blacklist_db(): create_funcs = [createAddressDB, createPeerDB, - createBlockDB, createBlockDataDB, createForwardKeyDB, create_blacklist_db] \ No newline at end of file diff --git a/src/onionrstorage/__init__.py b/src/onionrstorage/__init__.py deleted file mode 100755 index 1b964d46..00000000 --- a/src/onionrstorage/__init__.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Onionr - Private P2P Communication. - -Handle block storage, providing an abstraction for -storing blocks between file system and database -""" -import sys -import sqlite3 -import os -from onionrutils import bytesconverter -from onionrutils import stringvalidators -from coredb import dbfiles -from filepaths import block_data_location -import onionrexceptions -from onionrcrypto import hashers -from . import setdata, removeblock -from etc.onionrvalues import DATABASE_LOCK_TIMEOUT, BLOCK_EXPORT_FILE_EXT -""" - 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 . -""" - - -DB_ENTRY_SIZE_LIMIT = 10000 # Will be a config option - -set_data = setdata.set_data - - -def _dbInsert(block_hash, data): - conn = sqlite3.connect(dbfiles.block_data_db, - timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - data = (block_hash, data) - c.execute('INSERT INTO blockData (hash, data) VALUES(?, ?);', data) - conn.commit() - conn.close() - - -def _dbFetch(block_hash): - conn = sqlite3.connect(dbfiles.block_data_db, - timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - for i in c.execute( - 'SELECT data from blockData where hash = ?', (block_hash,)): - return i[0] - conn.commit() - conn.close() - return None - - -def deleteBlock(block_hash): - # Call removeblock.remove_block to automatically want to remove storage byte count - if os.path.exists(f'{block_data_location}/{block_hash}{BLOCK_EXPORT_FILE_EXT}'): - os.remove(f'{block_data_location}/{block_hash}{BLOCK_EXPORT_FILE_EXT}') - return True - conn = sqlite3.connect(dbfiles.block_data_db, - timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - data = (block_hash,) - c.execute('DELETE FROM blockData where hash = ?', data) - conn.commit() - conn.close() - return True - - -def store(data, block_hash=''): - if not stringvalidators.validate_hash(block_hash): - raise ValueError - ourHash = hashers.sha3_hash(data) - if block_hash != '': - if not ourHash == block_hash: - raise ValueError('Hash specified does not meet internal hash check') - else: - block_hash = ourHash - - if DB_ENTRY_SIZE_LIMIT >= sys.getsizeof(data): - _dbInsert(block_hash, data) - else: - with open( - f'{block_data_location}/{block_hash}{BLOCK_EXPORT_FILE_EXT}', 'wb') as blck_file: - blck_file.write(data) - - -def getData(bHash): - - if not stringvalidators.validate_hash(bHash): - raise ValueError - - bHash = bytesconverter.bytes_to_str(bHash) - bHash = bHash.strip() - # First check DB for data entry by hash - # if no entry, check disk - # If no entry in either, raise an exception - ret_data = None - fileLocation = '%s/%s%s' % ( - block_data_location, - bHash, BLOCK_EXPORT_FILE_EXT) - not_found_msg = "Block data not found for: " + str(bHash) - if os.path.exists(fileLocation): - with open(fileLocation, 'rb') as block: - ret_data = block.read() - else: - ret_data = _dbFetch(bHash) - - if ret_data is None: - raise onionrexceptions.NoDataAvailable(not_found_msg) - return ret_data diff --git a/src/onionrstorage/removeblock.py b/src/onionrstorage/removeblock.py deleted file mode 100644 index 6b9452ea..00000000 --- a/src/onionrstorage/removeblock.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Onionr - Private P2P Communication. - -remove onionr block from meta db -""" -import sys -import sqlite3 - -import onionrexceptions -import onionrstorage -from onionrutils import stringvalidators -from coredb import dbfiles -from onionrblocks import storagecounter -from etc.onionrvalues import DATABASE_LOCK_TIMEOUT -""" - 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 . -""" -storage_counter = storagecounter.StorageCounter() - - -def remove_block(block): - """Remove a block from this node. - - (does not automatically blacklist). - **You may want blacklist.addToDB(blockHash) - """ - if stringvalidators.validate_hash(block): - try: - data_size = sys.getsizeof(onionrstorage.getData(block)) - except onionrexceptions.NoDataAvailable: - data_size = 0 - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - t = (block,) - c.execute('Delete from hashes where hash=?;', t) - conn.commit() - conn.close() - if data_size: - storage_counter.remove_bytes(data_size) - else: - raise onionrexceptions.InvalidHexHash diff --git a/src/onionrstorage/setdata.py b/src/onionrstorage/setdata.py deleted file mode 100644 index 502ec086..00000000 --- a/src/onionrstorage/setdata.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Onionr - Private P2P Communication. - -Test Onionr as it is running -""" -import sys -import sqlite3 - -import onionrstorage -import onionrexceptions -import onionrcrypto as crypto -import filepaths -from onionrblocks import storagecounter, blockmetadata -from coredb import dbfiles -from onionrutils import bytesconverter -from etc.onionrvalues import DATABASE_LOCK_TIMEOUT -from onionrtypes import BlockHash -""" - 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 . -""" -storage_counter = storagecounter.StorageCounter() - - -def set_data(data): - """Set the data assciated with a hash.""" - dataSize = sys.getsizeof(data) - nonce_hash = crypto.hashers.sha3_hash( - bytesconverter.str_to_bytes( - blockmetadata.fromdata.get_block_metadata_from_data(data)[2])) - nonce_hash = bytesconverter.bytes_to_str(nonce_hash) - - if not type(data) is bytes: - data = data.encode() - - dataHash = crypto.hashers.sha3_hash(data) - - if type(dataHash) is bytes: - dataHash = dataHash.decode() - try: - onionrstorage.getData(dataHash) - except onionrexceptions.NoDataAvailable: - if storage_counter.add_bytes(dataSize): - onionrstorage.store(data, block_hash=dataHash) - conn = sqlite3.connect( - dbfiles.block_meta_db, timeout=DATABASE_LOCK_TIMEOUT) - c = conn.cursor() - c.execute( - "UPDATE hashes SET dataSaved=1 WHERE hash = ?;", - (dataHash,)) - conn.commit() - conn.close() - with open(filepaths.data_nonce_file, 'a') as nonceFile: - nonceFile.write(nonce_hash + '\n') - else: - raise onionrexceptions.DiskAllocationReached - else: - raise onionrexceptions.DataExists( - "Data is already set for " + dataHash) - - return dataHash diff --git a/src/onionrutils/importnewblocks.py b/src/onionrutils/importnewblocks.py deleted file mode 100644 index 11ae89c5..00000000 --- a/src/onionrutils/importnewblocks.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Onionr - Private P2P Communication. - -import new blocks from disk, providing transport agnosticism -""" -import glob - -import logger -from onionrblocks import blockmetadata -from coredb import blockmetadb -import filepaths -import onionrcrypto as crypto -from etc.onionrvalues import BLOCK_EXPORT_FILE_EXT -""" - 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 . -""" - - -def import_new_blocks(scanDir=''): - """Scan for new blocks ON THE DISK and import them""" - blockList = blockmetadb.get_block_list() - exist = False - if scanDir == '': - scanDir = filepaths.block_data_location - if not scanDir.endswith('/'): - scanDir += '/' - for block in glob.glob(scanDir + "*%s" % (BLOCK_EXPORT_FILE_EXT,)): - if block.replace(scanDir, '').replace(BLOCK_EXPORT_FILE_EXT, '') \ - not in blockList: - exist = True - logger.info('Found new block on dist %s' % block, terminal=True) - with open(block, 'rb') as newBlock: - block = block.replace(scanDir, '').replace( - BLOCK_EXPORT_FILE_EXT, '') - if crypto.hashers.sha3_hash(newBlock.read()) == block.replace( - BLOCK_EXPORT_FILE_EXT, ''): - blockmetadb.add_to_block_DB(block.replace( - BLOCK_EXPORT_FILE_EXT, ''), dataSaved=True) - logger.info('Imported block %s' % block, terminal=True) - blockmetadata.process_block_metadata(block) - else: - logger.warn('Failed to verify hash for %s' % block, - terminal=True) - if not exist: - logger.info('No blocks found to import', terminal=True) - - -import_new_blocks.onionr_help = \ - f"Scan the Onionr data directory under {filepaths.block_data_location}" + \ - "for new block files (.db not supported) to import" diff --git a/src/runtests/__init__.py b/src/runtests/__init__.py index addc0edf..4e7f6ee0 100644 --- a/src/runtests/__init__.py +++ b/src/runtests/__init__.py @@ -8,12 +8,9 @@ from secrets import SystemRandom import logger from onionrutils import epoch -from . import uicheck, inserttest, stresstest +from . import uicheck from .webpasstest import webpass_test from .osver import test_os_ver_endpoint -from .clearnettor import test_clearnet_tor_request -from .housekeeping import test_inserted_housekeeping -from .sneakernettest import test_sneakernet_import from .dnsrebindingtest import test_dns_rebinding """ This program is free software: you can redistribute it and/or modify @@ -31,14 +28,8 @@ from .dnsrebindingtest import test_dns_rebinding """ RUN_TESTS = [uicheck.check_ui, - inserttest.insert_bin_test, - stresstest.stress_test_block_insert, webpass_test, test_os_ver_endpoint, - test_clearnet_tor_request, - test_inserted_housekeeping, - sneakernettest.test_sneakernet_import, - test_dns_rebinding ] SUCCESS_FILE = os.path.dirname(os.path.realpath(__file__)) + '/../../tests/runtime-result.txt' diff --git a/src/runtests/clearnettor.py b/src/runtests/clearnettor.py deleted file mode 100644 index e17bc9bb..00000000 --- a/src/runtests/clearnettor.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Onionr - Private P2P Communication. - -Ensure that clearnet cannot be reached -""" -from onionrutils.basicrequests import do_get_request -from onionrutils import localcommand -import logger -import config -""" - 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 . -""" - - -def test_clearnet_tor_request(testmanager): - """Ensure that Tor cannot request clearnet address. - - Does not run if Tor is being reused - """ - - config.reload() - leak_result = "" - - if config.get('tor.use_existing_tor', False): - logger.warn( - "Can't ensure Tor reqs to clearnet won't happen when reusing Tor") - return - - - socks_port = localcommand.local_command('/gettorsocks') - - # Don't worry, this request isn't meant to go through, - # but if it did it would be through Tor - - try: - leak_result: str = do_get_request( - 'https://example.com/notvalidpage', - port=socks_port, ignoreAPI=True).lower() - except AttributeError: - leak_result = "" - except Exception as e: - logger.warn(str(e)) - try: - if 'example' in leak_result: - logger.error('Tor was able to request a clearnet site') - raise ValueError('Tor was able to request a clearnet site') - except TypeError: - pass diff --git a/src/runtests/housekeeping.py b/src/runtests/housekeeping.py deleted file mode 100644 index ccc46b9f..00000000 --- a/src/runtests/housekeeping.py +++ /dev/null @@ -1,25 +0,0 @@ -import os - -from gevent import sleep - -from onionrblocks import insert -import logger -from coredb.blockmetadb import get_block_list -from onionrutils import epoch - - -def test_inserted_housekeeping(testmanager): - """Tests that inserted blocks are proprely deleted""" - bl = insert('testdata', expire=12) - wait_seconds = 132 # Wait two minutes plus expire time - count = 0 - if bl in get_block_list(): - while count < wait_seconds: - if bl in get_block_list(): - sleep(0.8) - count += 1 - else: - return - raise ValueError('Inserted block with expiry not erased') - else: - raise ValueError('Inserted block in expiry test not present in list') diff --git a/src/runtests/inserttest.py b/src/runtests/inserttest.py deleted file mode 100644 index 12b78558..00000000 --- a/src/runtests/inserttest.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -import time - -import onionrblocks -import logger -import coredb - -def _check_remote_node(testmanager): - return - -def insert_bin_test(testmanager): - data = os.urandom(32) - b_hash = onionrblocks.insert(data) - time.sleep(0.3) - if b_hash not in testmanager._too_many.get_by_string("PublicAPI").hideBlocks: - raise ValueError("Block not hidden") - - if b_hash not in coredb.blockmetadb.get_block_list(): - logger.error(str(b_hash) + 'is not in bl') - raise ValueError diff --git a/src/runtests/sneakernettest.py b/src/runtests/sneakernettest.py deleted file mode 100644 index ac48ad30..00000000 --- a/src/runtests/sneakernettest.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -from shutil import move - -from onionrblocks import insert -from onionrstorage import deleteBlock -from onionrcommands.exportblocks import export_block -from filepaths import export_location, block_data_location, data_nonce_file -from etc.onionrvalues import BLOCK_EXPORT_FILE_EXT -from onionrstorage.removeblock import remove_block -from onionrstorage import deleteBlock -from coredb.blockmetadb import get_block_list -from utils import bettersleep -from gevent import sleep - -def test_sneakernet_import(test_manager): - in_db = lambda b: b in get_block_list() - bl = insert(os.urandom(10)) - assert in_db(bl) - export_block(bl) - assert os.path.exists(export_location + bl + BLOCK_EXPORT_FILE_EXT) - remove_block(bl) - deleteBlock(bl) - assert not in_db(bl) - os.remove(data_nonce_file) - move(export_location + bl + BLOCK_EXPORT_FILE_EXT, block_data_location) - sleep(1) - assert in_db(bl) diff --git a/src/runtests/stresstest.py b/src/runtests/stresstest.py deleted file mode 100644 index 35a9967c..00000000 --- a/src/runtests/stresstest.py +++ /dev/null @@ -1,17 +0,0 @@ -import os - -import onionrblocks -import logger -import coredb -from onionrutils import epoch - -def stress_test_block_insert(testmanager): - return - start = epoch.get_epoch() - count = 100 - max_insert_speed = 120 - for x in range(count): onionrblocks.insert(os.urandom(32)) - speed = epoch.get_epoch() - start - if speed < max_insert_speed: - raise ValueError(f'{count} blocks inserted too fast, {max_insert_speed}, got {speed}') - logger.info(f'runtest stress block insertion: {count} blocks inserted in {speed}s') diff --git a/src/sneakernet/__init__.py b/src/sneakernet/__init__.py deleted file mode 100644 index 6b4002a8..00000000 --- a/src/sneakernet/__init__.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Onionr - Private P2P Communication. - -Detect new block files in a given directory -""" -import os - -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -import config -from filepaths import block_data_location -from etc.onionrvalues import BLOCK_EXPORT_FILE_EXT -from onionrblocks.blockimporter import import_block_from_data -import onionrexceptions -""" - 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 . -""" - -watch_paths = config.get('transports.sneakernet.paths', list([])) -if block_data_location not in watch_paths: - watch_paths.append(block_data_location) - - -class _Importer(FileSystemEventHandler): - @staticmethod - def on_created(event): - if not event.src_path.endswith(BLOCK_EXPORT_FILE_EXT): - return - try: - with open(event.src_path, 'rb') as block_file: - block_data = block_file.read() - except FileNotFoundError: - return - os.remove(event.src_path) - try: - import_block_from_data(block_data) - except( # noqa - onionrexceptions.DataExists, - onionrexceptions.BlockMetaEntryExists, - onionrexceptions.InvalidMetadata) as _: - return - if block_data_location in event.src_path: - try: - os.remove(event.src_path) - except FileNotFoundError: - pass - - -def sneakernet_import_thread(): - """Add block data dir & confed paths to fs observer to watch for new bls""" - observer = Observer() - for path in watch_paths: - observer.schedule(_Importer(), path, recursive=True) - observer.start() - while observer.is_alive(): - # call import func with timeout - observer.join(60) diff --git a/static-data/default-plugins/circles/flowapi.py b/static-data/default-plugins/circles/flowapi.py deleted file mode 100755 index 30668e97..00000000 --- a/static-data/default-plugins/circles/flowapi.py +++ /dev/null @@ -1,123 +0,0 @@ -"""Onionr - Private P2P Communication. - -This file primarily serves to allow specific fetching of circles board messages -""" -import operator -import os - -import ujson as json - -from flask import Response, Blueprint -from flask import send_from_directory -from deadsimplekv import DeadSimpleKV - -from utils import identifyhome -""" - 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 . -""" - -flask_blueprint = Blueprint('circles', __name__) - -root = os.path.dirname(os.path.realpath(__file__)) - - -with open( - os.path.dirname( - os.path.realpath(__file__)) + '/info.json', 'r') as info_file: - data = info_file.read().strip() - version = json.loads(data)['version'] - -BOARD_CACHE_FILE = identifyhome.identify_home() + '/board-index.cache.json' - -read_only_cache = DeadSimpleKV( - BOARD_CACHE_FILE, - flush_on_exit=False, - refresh_seconds=30) - -@flask_blueprint.route('/board/', endpoint='circlesstatic') -def load_mail(path): - return send_from_directory(root + '/web/', path) - - -@flask_blueprint.route('/board/', endpoint='circlesindex') -def load_mail_index(): - return send_from_directory(root + '/web/', 'index.html') - - -@flask_blueprint.route('/circles/getpostsbyboard/') -def get_post_by_board(board): - board_cache = DeadSimpleKV( - BOARD_CACHE_FILE, - flush_on_exit=False) - board_cache.refresh() - posts = board_cache.get(board) - if posts is None: - posts = '' - else: - posts = ','.join(posts) - return Response(posts) - - -@flask_blueprint.route('/circles/getpostsbyboard//') -def get_post_by_board_with_offset(board, offset): - offset = int(offset) - OFFSET_COUNT = 10 - board_cache = DeadSimpleKV( - BOARD_CACHE_FILE, - flush_on_exit=False) - board_cache.refresh() - posts = board_cache.get(board) - if posts is None: - posts = '' - else: - posts.reverse() - posts = ','.join(posts[offset:offset + OFFSET_COUNT]) - return Response(posts) - - -@flask_blueprint.route('/circles/version') -def get_version(): - return Response(version) - - -@flask_blueprint.route('/circles/removefromcache//', - methods=['POST']) -def remove_from_cache(board, name): - board_cache = DeadSimpleKV(BOARD_CACHE_FILE, - flush_on_exit=False) - board_cache.refresh() - posts = board_cache.get(board) - try: - posts.remove(name) - except ValueError: - pass - board_cache.put(board, posts) - return Response('success') - - -@flask_blueprint.route('/circles/getpopular/') -def get_popular(count): - read_only_cache.refresh() - boards = json.loads(read_only_cache.get_raw_json()) - for board in boards: - boards[board] = len(boards[board]) - - - top_boards = sorted(boards.items(), key=operator.itemgetter(1), reverse=True)[:int(count)] - - only_board_names = [] - for b in top_boards: - only_board_names.append(b[0]) - - return Response(','.join(only_board_names), content_type='text/csv') diff --git a/static-data/default-plugins/circles/info.json b/static-data/default-plugins/circles/info.json deleted file mode 100755 index 9e140e29..00000000 --- a/static-data/default-plugins/circles/info.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "name": "circles", - "version": "1.0.0", - "author": "onionr" -} \ No newline at end of file diff --git a/static-data/default-plugins/circles/main.py b/static-data/default-plugins/circles/main.py deleted file mode 100755 index 51e7815a..00000000 --- a/static-data/default-plugins/circles/main.py +++ /dev/null @@ -1,176 +0,0 @@ -"""Onionr - Private P2P Communication. - -This default plugin handles "flow" messages -(global chatroom style communication) -""" -import sys -import os -import deadsimplekv as simplekv -from utils import identifyhome, reconstructhash -from coredb import blockmetadb -import threading -import time -import locale -from onionrblocks.onionrblockapi import Block -import logger -import onionrblocks -from onionrutils import escapeansi, epoch, bytesconverter - -locale.setlocale(locale.LC_ALL, '') -sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) -# import after path insert -import flowapi # noqa -""" - 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 . -""" - -flask_blueprint = flowapi.flask_blueprint -security_whitelist = ['circles.circlesstatic', 'circles.circlesindex'] - -plugin_name = 'circles' -PLUGIN_VERSION = '0.1.0' - -EXPIRE_TIME = 43200 - -class OnionrFlow: - def __init__(self): - self.alreadyOutputed = [] - self.flowRunning = False - self.channel = "" - return - - def start(self): - logger.warn( - "Please note: everything said here is public, " + - "even if a random channel name is used.", terminal=True) - message = "" - self.flowRunning = True - try: - self.channel = logger.readline( - "Enter a channel name or none for default:").strip() - except (KeyboardInterrupt, EOFError): - self.flowRunning = False - newThread = threading.Thread(target=self.showOutput, daemon=True) - newThread.start() - while self.flowRunning: - if self.channel == "": - self.channel = "global" - try: - message = logger.readline(f'\nInsert message into {plugin_name}:').strip().replace( - '\n', '\\n').replace('\r', '\\r') - except EOFError: - pass - except KeyboardInterrupt: - self.flowRunning = False - else: - if message == "q": - self.flowRunning = False - expireTime = epoch.get_epoch() + EXPIRE_TIME - if len(message) > 0: - logger.info('Inserting message as block...', terminal=True) - onionrblocks.insert(message, header='brd', - expire=expireTime, - meta = { - 'ch': self.channel}) - - logger.info(f"{plugin_name} is exiting, goodbye", terminal=True) - return - - def showOutput(self): - while isinstance(self.channel, type(None)) and self.flowRunning: - time.sleep(1) - try: - while self.flowRunning: - for block in blockmetadb.get_blocks_by_type('brd'): - if block in self.alreadyOutputed: - continue - block = Block(block) - b_hash = bytesconverter.bytes_to_str(block.getHash()) - if block.getMetadata('ch') != self.channel: - continue - if not self.flowRunning: - break - logger.info('\n------------------------', - prompt=False, terminal=True) - content = block.getContent() - # Escape new lines, remove trailing whitespace, and escape ansi sequences - content = escapeansi.escape_ANSI(content.replace( - b'\n', b'\\n').replace(b'\r', b'\\r').strip().decode('utf-8')) - logger.info(block.getDate().strftime( - "%m/%d %H:%M") + ' - ' + - logger.colors.reset + content, - prompt=False, terminal=True) - self.alreadyOutputed.append(b_hash) - time.sleep(5) - except KeyboardInterrupt: - self.flowRunning = False - - -def on_circles_cmd(api, data=None): - OnionrFlow().start() - - -def on_circlesend_cmd(api, data=None): - err_msg = "Second arg is board name, third is quoted message" - try: - sys.argv[2] - except IndexError: - logger.error(err_msg, terminal=True) - try: - sys.argv[3] - except IndexError: - logger.error(err_msg, terminal=True) - - bl = onionrblocks.insert(sys.argv[3], header='brd', - expire=(EXPIRE_TIME + epoch.get_epoch()), - meta={'ch': sys.argv[2]}) - print(bl) - - - -def on_softreset(api, data=None): - try: - os.remove(identifyhome.identify_home() + '/board-index.cache.json') - logger.info('Cleared Circles board cache') - except FileNotFoundError: - pass - - -def on_processblocks(api, data=None): - metadata = data['block'].bmetadata # Get the block metadata - if data['type'] != 'brd': - return - - b_hash = reconstructhash.deconstruct_hash( - data['block'].hash) # Get the 0-truncated block hash - board_cache = simplekv.DeadSimpleKV(identifyhome.identify_home( - ) + '/board-index.cache.json', flush_on_exit=False) # get the board index cache - board_cache.refresh() - # Validate the channel name is sane for caching - try: - ch = metadata['ch'] - except KeyError: - ch = 'global' - ch_len = len(ch) - if ch_len == 0: - ch = 'global' - elif ch_len > 12: - return - - existing_posts = board_cache.get(ch) - if existing_posts is None: - existing_posts = [] - existing_posts.append(data['block'].hash) - board_cache.put(ch, existing_posts) - board_cache.flush() diff --git a/static-data/default-plugins/circles/web/autorefresh.js b/static-data/default-plugins/circles/web/autorefresh.js deleted file mode 100644 index bb41fde1..00000000 --- a/static-data/default-plugins/circles/web/autorefresh.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - Onionr - Private P2P Communication - - Auto refresh board posts - - 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 . -*/ -var checkbox = document.getElementById('refreshCheckbox') -function autoRefresh(){ - if (! checkbox.checked || document.hidden){return} - getBlocks() -} - -function setupInterval(){ - if (checkbox.checked){ - refreshInterval = setInterval(autoRefresh, 3000) - autoRefresh() - return - } - clearInterval(refreshInterval) -} - -var refreshInterval = setInterval(autoRefresh, 3000) -setupInterval() - -checkbox.onchange = function(){setupInterval} - - -document.addEventListener("visibilitychange", function() { - if (document.visibilityState === 'visible') { - autoRefresh() - } - }) diff --git a/static-data/default-plugins/circles/web/board.js b/static-data/default-plugins/circles/web/board.js deleted file mode 100755 index 8a2a3be5..00000000 --- a/static-data/default-plugins/circles/web/board.js +++ /dev/null @@ -1,265 +0,0 @@ -/* - Onionr - Private P2P Communication - - This file handles the boards/circles interface - - 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 . -*/ -requested = [] -newPostForm = document.getElementById('addMsg') -firstLoad = true -lastLoadedBoard = 'global' -loadingMessage = document.getElementById('loadingBoard') -loadedAny = false -loadingTimeout = 8000 - -let toggleLoadingMessage = function(){ - switch (loadingMessage.style.display){ - case "inline-block": - loadingMessage.style.display = "none" - break; - default: - loadingMessage.style.display = "initial" - break; - } -} - -fetch('/circles/version', { - method: 'GET', - headers: { - "token": webpass -}}) -.then((ver) => ver.text()) -.then(function(ver) { - document.getElementById('circlesVersion').innerText = ver -}) - -function appendMessages(msg, blockHash, beforeHash, channel) { - if (channel !== document.getElementById('feedIDInput').value) return // ignore if channel name isn't matching - if (msg.length == 0) return // ignore empty messages - - var humanDate = new Date(0) - var msgDate = msg['meta']['time'] - var feed = document.getElementById("feed") - var beforeEl = null - - if (msgDate === undefined){ - msgDate = 'unknown' - } else { - humanDate.setUTCSeconds(msgDate) - msgDate = humanDate.toLocaleString("en-US", {timeZone: "Etc/GMT"}) - } - - var el = document.createElement('div') - el.innerText = msg['content'] - - if (beforeHash !== null) { - for (i = 0; i < feed.children.length; i++) { - if (feed.children[i].getAttribute('data-bl') === beforeHash) { - beforeEl = feed.children[i] - } - } - } - - /* Template Test */ - // Test to see if the browser supports the HTML template element by checking - // for the presence of the template element's content attribute. - if ('content' in document.createElement('template')) { - - // Instantiate the table with the existing HTML tbody - // and the row with the template - var template = document.getElementById('cMsgTemplate') - - // Clone the new row and insert it into the table - var clone = document.importNode(template.content, true) - var div = clone.querySelectorAll("div") - var identicon = clone.querySelectorAll("img") - - div[0].classList.add('entry') - div[0].setAttribute('timestamp', msg['meta']['time']) - - div[0].setAttribute('data-bl', blockHash) - div[2].textContent = msg['content'] - if (typeof msg['meta']['signer'] != 'undefined' && msg['meta']['signer'].length > 0){ - div[3].textContent = msg['meta']['signer'].substr(0, 5) - setHumanReadableIDOnPost(div[3], msg['meta']['signer']) - div[3].onclick = function(){ - navigator.clipboard.writeText(div[3].title).then(function() { - PNotify.notice("Copied poster identity to clipboard") - }) - } - div[3].title = msg['meta']['signer'] - userIcon(msg['meta']['signer']).then(function(data){ - identicon[0].src = "data:image/svg+xml;base64," + data - }) - } - else{ - identicon[0].remove() - } - div[4].textContent = msgDate - - loadingMessage.style.display = "none" - loadedAny = true - if (firstLoad){ - //feed.appendChild(clone) - feed.prepend(clone) - firstLoad = false - } - else{ - if (beforeEl === null){ - feed.prepend(clone) - } - else{ - beforeEl.insertAdjacentElement("beforebegin", clone.children[0]) - } - - } - } -} - -function getBlocks(){ - var feed = document.getElementById("feed") - var ch = document.getElementById('feedIDInput').value - if (lastLoadedBoard !== ch){ - requested = [] - - toggleLoadingMessage() - loadedAny = false - - while (feed.firstChild) feed.removeChild(feed.firstChild); // remove all messages from feed - - setTimeout(function(){ - if (! loadedAny && ch == document.getElementById('feedIDInput').value){ - PNotify.notice("There are no posts for " + ch + ". You can be the first!") - } - }, loadingTimeout) - } - - lastLoadedBoard = ch - if (document.getElementById('none') !== null){ - document.getElementById('none').remove(); - - } - - fetch('/circles/getpostsbyboard/' + ch, { - method: 'GET', - headers: { - "token": webpass - }}) - .then((resp) => resp.text()) - .then(function(feedText) { - var blockList = feedText.split(',') - - for (i = 0; i < blockList.length; i++){ - blockList[i] = "0".repeat(64 - blockList[i].length) + blockList[i] // pad hash with zeroes - - if (! requested.includes(blockList[i])){ - if (blockList[i].length == 0) continue - else requested.push(blockList[i]) - loadMessage(blockList[i], blockList, i, ch); - } - } - sortEntries() - }) -} - -function loadMessage(blockHash, blockList, count, channel){ - if (blockHash == '0000000000000000000000000000000000000000000000000000000000000000'){ - return - } - fetch('/getblockdata/' + blockHash, { - method: 'GET', - headers: { - "token": webpass - }}).then(function(response) { - if (!response.ok) { - let on404 = function() { - if (response.status == 404){ - fetch('/circles/removefromcache/' + channel + '/' + blockHash, { - method: 'POST', - headers: { - "content-type": "application/json", - "token": webpass - } - }) - } - else{ - console.log(error) - } - }() - return - } - response.json().then(function(data){ - let before = blockList[count - 1] - let delay = 2000 - if (typeof before == "undefined"){ - before = null - } else { - let existing = document.getElementsByClassName('cMsgBox') - for (x = 0; x < existing.length; x++){ - if (existing[x].getAttribute('data-bl') === before){ - delay = 0 - } - } - } - setTimeout(function(){appendMessages(data, blockHash, before, channel)}, delay) - }) - return response; - }) -} - -document.getElementById('refreshFeed').onclick = function() { - getBlocks() -} - -newPostForm.onsubmit = function(){ - var message = document.getElementById('newMsgText').value - var channel = document.getElementById('feedIDInput').value - var meta = {'ch': channel} - let doSign = document.getElementById('postAnon').checked - var postData = {'message': message, 'sign': doSign, 'type': 'brd', 'encrypt': false, 'meta': JSON.stringify(meta)} - postData = JSON.stringify(postData) - newPostForm.style.display = 'none' - fetch('/insertblock', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - } - }) - .then((resp) => resp.text()) - .then(function(data) { - newPostForm.style.display = 'block' - if (data == 'failure due to duplicate insert'){ - PNotify.error({ - text: "This message is already queued" - }) - return - } - PNotify.success({ - text: "Message queued for posting" - }) - setTimeout(function(){getBlocks()}, 500) - }) - return false -} - -resetCirclePickers = function(){ - document.getElementById('recommendedBoards').value = "" - document.getElementById('popularBoards').value = "" -} - -document.getElementById('feedIDInput').onchange = resetCirclePickers - diff --git a/static-data/default-plugins/circles/web/default-circle-picker.js b/static-data/default-plugins/circles/web/default-circle-picker.js deleted file mode 100644 index 4b6e29c2..00000000 --- a/static-data/default-plugins/circles/web/default-circle-picker.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - Onionr - Private P2P Communication - - Handle default board picker - - 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 . -*/ - -recommendedIDs = document.getElementById('recommendedBoards') - -recommendedIDs.onchange = function(){ - document.getElementById('feedIDInput').value = recommendedIDs.value - getBlocks() - resetCirclePickers() -} \ No newline at end of file diff --git a/static-data/default-plugins/circles/web/detect-plaintext-storage.js b/static-data/default-plugins/circles/web/detect-plaintext-storage.js deleted file mode 100644 index de16f57f..00000000 --- a/static-data/default-plugins/circles/web/detect-plaintext-storage.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - Onionr - Private P2P Communication - - detect for Circles if plaintext insert/storage is enabled - - 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 . -*/ -plaintext_enabled = null - -fetch('/config/get/general.store_plaintext_blocks', { - method: 'GET', - headers: { - "token": webpass - }}) -.then((resp) => resp.text()) -.then(function(data) { - plaintext_enabled = true - if (data == "false"){ - plaintext_enabled = false - PNotify.error({ - text: "Plaintext storage is disabled. You will not be able to see new posts or make posts yourself" - }) - } -}) diff --git a/static-data/default-plugins/circles/web/index.html b/static-data/default-plugins/circles/web/index.html deleted file mode 100755 index 2b4b7a52..00000000 --- a/static-data/default-plugins/circles/web/index.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - Circles - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

- Circles v -

-

- Anonymous message boards -

-
-
-
-
- -
- - -
-
- -
-
-
-
-

- Post message -

-
-
-
- -
-
- -
-
-
- -
-
-
-

- Feed -

-
-
-
-
-
-

- Circle Name -

-

- -

-

- Refresh Feed -

-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-

-
- Note: All posts in Circles are publicly accessible. -

- - -
- - -
-
-
- -
- None yet, try refreshing 😃 - -
-
-
-
-
-
-
- - - - - - \ No newline at end of file diff --git a/static-data/default-plugins/circles/web/popular.js b/static-data/default-plugins/circles/web/popular.js deleted file mode 100644 index 9fffb301..00000000 --- a/static-data/default-plugins/circles/web/popular.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - Onionr - Private P2P Communication - - Load popular boards and show them in the UI. Handle selections of popular boards. - - 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 . -*/ - - -fetch('/circles/getpopular/8', { - method: 'GET', - headers: { - "token": webpass -}}) -.then((popular) => popular.text()) -.then(function(popular) { - var popularSelect = document.getElementById('popularBoards') - let boards = popular.split(',') - for (board of boards){ - let newOption = document.createElement('option') - if (board == ""){continue} - newOption.value = board - newOption.innerText = board.charAt(0).toUpperCase() + board.slice(1) - console.debug(board) - popularSelect.appendChild(newOption) - } -}) - -document.getElementById('popularBoards').onchange = function(){ - document.getElementById('feedIDInput').value = document.getElementById('popularBoards').value - getBlocks() - resetCirclePickers() -} - diff --git a/static-data/default-plugins/circles/web/sethumanreadable.js b/static-data/default-plugins/circles/web/sethumanreadable.js deleted file mode 100644 index 0d8f6eee..00000000 --- a/static-data/default-plugins/circles/web/sethumanreadable.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - Onionr - Private P2P Communication - - Set human readable public keys onto post author elements - - 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 . -*/ -humanReadableKeys = {} - -function setHumanReadableIDOnPost(el, key){ - if (typeof humanReadableKeys[key] == "undefined"){ - fetch('/getHumanReadable/' + key, { - method: 'GET', - headers: { - "token": webpass - }}) - .then((resp) => resp.text()) // Transform the data into json - .then(function(data) { - if (data.includes('HTML')){ - return - } - humanReadableKeys[key] = data - setHumanReadableIDOnPost(el, key) - }) - return - } - el.innerText = humanReadableKeys[key].split('-').slice(0, 3).join(' ') -} \ No newline at end of file diff --git a/static-data/default-plugins/circles/web/sort-posts.js b/static-data/default-plugins/circles/web/sort-posts.js deleted file mode 100644 index 59b9f880..00000000 --- a/static-data/default-plugins/circles/web/sort-posts.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - Onionr - Private P2P Communication - - Sort post entries - - 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 . -*/ - -function sortEntries() { - var entries = document.getElementsByClassName('entry') - - if (entries.length > 1) { - const sortBy = 'timestamp' - const parent = entries[0].parentNode - - const sorted = Array.from(entries).sort((a, b) => b.getAttribute(sortBy) - a.getAttribute(sortBy)) - sorted.forEach(element => parent.appendChild(element)) - } -} diff --git a/static-data/default-plugins/circles/web/theme.css b/static-data/default-plugins/circles/web/theme.css deleted file mode 100755 index fa7ebd7c..00000000 --- a/static-data/default-plugins/circles/web/theme.css +++ /dev/null @@ -1,12 +0,0 @@ - -.cMsg{ - word-wrap:break-word; - word-break:break-word; - white-space: pre-wrap; - overflow: hidden; -} - -body{ - background-color: #212224; - color: white; -} diff --git a/static-data/default-plugins/debuginfo/debugapi.py b/static-data/default-plugins/debuginfo/debugapi.py deleted file mode 100755 index d3b06ce5..00000000 --- a/static-data/default-plugins/debuginfo/debugapi.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Onionr - Private P2P Communication. - -This file primarily serves to allow specific fetching of circles board messages -""" -from flask import Response, Blueprint, g - -from deadsimplekv import DeadSimpleKV - -""" - 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 . -""" - -flask_blueprint = Blueprint('debugAPI', __name__) - - -@flask_blueprint.route('/debug/dump_shared_state') -def get_shared_state() -> Response: - """Return somewhat human-readable dump of shared toomanyobjects.""" - resp = "" - for i in g.too_many.objects.keys: - resp += i + dir(g.too_many.objects.keys[i]) + "\n" - return Response(resp) - - -@flask_blueprint.route('/debug/dump_shared_vars') -def get_shared_vars() -> Response: - """Return somewhat human-readable dump of pseudo globals (DeadSimpleKV).""" - kv: DeadSimpleKV = g.too_many.get(DeadSimpleKV) - resp = "" - for i in kv.keys: - resp += i + dir(g.too_many.objects.keys[i]) + "\n" - return Response(resp) - diff --git a/static-data/default-plugins/debuginfo/info.json b/static-data/default-plugins/debuginfo/info.json deleted file mode 100755 index 037c2854..00000000 --- a/static-data/default-plugins/debuginfo/info.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "name": "debug", - "version": "0.0.0", - "author": "onionr" -} \ No newline at end of file diff --git a/static-data/default-plugins/debuginfo/main.py b/static-data/default-plugins/debuginfo/main.py deleted file mode 100755 index 22eb4dd2..00000000 --- a/static-data/default-plugins/debuginfo/main.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Onionr - Private P2P Communication. - -Client HTTP API debug endpoints -""" -import sys -import os -import locale - -locale.setlocale(locale.LC_ALL, '') -sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) -# import after path insert -import debugapi # noqa -""" - 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 . -""" - -flask_blueprint = debugapi.flask_blueprint - -plugin_name = 'debuginfo' -PLUGIN_VERSION = '0.0.0' diff --git a/static-data/default-plugins/encrypt/info.json b/static-data/default-plugins/encrypt/info.json deleted file mode 100755 index d675197a..00000000 --- a/static-data/default-plugins/encrypt/info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name" : "encrypt", - "version" : "1.0", - "author" : "onionr" -} diff --git a/static-data/default-plugins/encrypt/main.py b/static-data/default-plugins/encrypt/main.py deleted file mode 100755 index feed4b03..00000000 --- a/static-data/default-plugins/encrypt/main.py +++ /dev/null @@ -1,130 +0,0 @@ -''' - Onionr - Private P2P Communication - - This default plugin allows users to encrypt/decrypt messages without using blocks -''' -''' - 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 . -''' - -# Imports some useful libraries -import logger, config, threading, time, datetime, sys - -import ujson as json -from nacl.exceptions import TypeError as NaclTypeError - -from onionrutils import stringvalidators, bytesconverter -from onionrcrypto import encryption, keypair, signing, getourkeypair -import onionrexceptions, onionrusers - -import locale -locale.setlocale(locale.LC_ALL, '') - -import binascii - -plugin_name = 'encrypt' - -class PlainEncryption: - def __init__(self, api): - self.api = api - return - def encrypt(self): - # peer, data - plaintext = "" - encrypted = "" - # detect if signing is enabled - sign = True - try: - if sys.argv[3].lower() == 'false': - sign = False - except IndexError: - pass - - try: - if not stringvalidators.validate_pub_key(sys.argv[2]): - raise onionrexceptions.InvalidPubkey - except (ValueError, IndexError) as e: - logger.error("Peer public key not specified", terminal=True) - except onionrexceptions.InvalidPubkey: - logger.error("Invalid public key", terminal=True) - else: - pubkey = sys.argv[2] - # Encrypt if public key is valid - logger.info("Please enter your message (ctrl-d or -q to stop):", terminal=True) - try: - for line in sys.stdin: - if line == '-q\n': - break - plaintext += line - except KeyboardInterrupt: - sys.exit(1) - # Build Message to encrypt - data = {} - myPub = keypair[0] - if sign: - data['sig'] = signing.ed_sign(plaintext, key=keypair[1], encodeResult=True) - data['sig'] = bytesconverter.bytes_to_str(data['sig']) - data['signer'] = myPub - data['data'] = plaintext - data = json.dumps(data) - plaintext = data - encrypted = encryption.pub_key_encrypt(plaintext, pubkey, encodedData=True) - encrypted = bytesconverter.bytes_to_str(encrypted) - logger.info('Encrypted Message: \n\nONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,), terminal=True) - - def decrypt(self): - plaintext = "" - data = "" - logger.info("Please enter your message (ctrl-d or -q to stop):", terminal=True) - keypair = getourkeypair.get_keypair() - try: - for line in sys.stdin: - if line == '-q\n': - break - data += line - except KeyboardInterrupt: - sys.exit(1) - if len(data) <= 1: - return - encrypted = data.replace('ONIONR ENCRYPTED DATA ', '').replace('END ENCRYPTED DATA', '') - myPub = keypair[0] - decrypted = encryption.pub_key_decrypt(encrypted, privkey=keypair[1], encodedData=True) - if decrypted == False: - logger.error("Decryption failed", terminal=True) - else: - data = json.loads(decrypted) - logger.info('Decrypted Message: \n\n%s' % data['data'], terminal=True) - try: - logger.info("Signing public key: %s" % (data['signer'],), terminal=True) - if not signing.ed_verify(data['data'], data['signer'], data['sig']): raise ValueError - except (ValueError, KeyError) as e: - logger.warn("WARNING: THIS MESSAGE HAS A MISSING OR INVALID SIGNATURE", terminal=True) - else: - logger.info("Message has good signature.", terminal=True) - return - -def on_decrypt_cmd(api, data=None): - try: - PlainEncryption(api).decrypt() - except binascii.Error: - logger.error("Invalid ciphertext padding", terminal=True) - except NaclTypeError: - logger.error("Ciphertext too short.", terminal=True) - -def on_encrypt_cmd(api, data=None): - PlainEncryption(api).encrypt() - -on_encrypt_cmd.onionr_help = """encrypt \nEncrypt text data to an Onionr user key. Similar to PGP""" -on_decrypt_cmd.onionr_help = """decrypt\nDecrypt text data with your Onionr key. Similar to PGP""" -ONIONR_COMMANDS = ['encrypt', 'decrypt'] \ No newline at end of file diff --git a/static-data/default-plugins/pms/info.json b/static-data/default-plugins/pms/info.json deleted file mode 100755 index 72ce2b39..00000000 --- a/static-data/default-plugins/pms/info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name" : "pms", - "version" : "0.1.2", - "author" : "onionr" -} diff --git a/static-data/default-plugins/pms/loadinbox.py b/static-data/default-plugins/pms/loadinbox.py deleted file mode 100755 index 6a215f71..00000000 --- a/static-data/default-plugins/pms/loadinbox.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Onionr - Private P2P Communication. - -Load the user's inbox and return it as a list -""" -from onionrblocks import onionrblockapi -from coredb import blockmetadb -from utils import reconstructhash, identifyhome -import deadsimplekv as simplekv -""" - 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 . -""" - -inbox_cache = {} -def load_inbox(): - inbox_list = [] - deleted = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/mailcache.dat').get('deleted_mail') - if deleted is None: - deleted = [] - - for blockHash in blockmetadb.get_blocks_by_type('pm'): - if blockHash in deleted: - continue - if blockHash in inbox_cache: - inbox_list.append(blockHash) - continue - block = onionrblockapi.Block(blockHash) - block.decrypt() - if block.decrypted and reconstructhash.deconstruct_hash(blockHash): - inbox_cache[blockHash] = True - inbox_list.append(blockHash) - return inbox_list diff --git a/static-data/default-plugins/pms/mailapi.py b/static-data/default-plugins/pms/mailapi.py deleted file mode 100755 index 53783a09..00000000 --- a/static-data/default-plugins/pms/mailapi.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Onionr - Private P2P Communication. - -HTTP endpoints for mail plugin -""" -import sys -import os - -import ujson as json -from flask import Response, request, redirect, Blueprint, abort -from flask import send_from_directory -import deadsimplekv as simplekv - -from httpapi.sse.wrapper import SSEWrapper -from onionrusers import contactmanager -from onionrutils import stringvalidators -from utils import reconstructhash, identifyhome -from utils.bettersleep import better_sleep as sleep - -sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) -import loadinbox -import sentboxdb -""" - 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 . -""" -flask_blueprint = Blueprint('mail', __name__) -kv = simplekv.DeadSimpleKV(identifyhome.identify_home() + '/mailcache.dat') -root = os.path.dirname(os.path.realpath(__file__)) - -sse_wrapper = SSEWrapper() - -@flask_blueprint.route('/mail/', endpoint='mailstatic') -def load_mail(path): - return send_from_directory(root + '/web/', path) - - -@flask_blueprint.route('/mail/', endpoint='mailindex') -def load_mail_index(): - return send_from_directory(root + '/web/', 'index.html') - - -@flask_blueprint.route('/mail/ping') -def mail_ping(): - return 'pong!' - -@flask_blueprint.route('/mail/deletemsg/', methods=['POST']) -def mail_delete(block): - if not stringvalidators.validate_hash(block): - abort(504) - block = reconstructhash.deconstruct_hash(block) - existing = kv.get('deleted_mail') - if existing is None: - existing = [] - if block not in existing: - existing.append(block) - kv.put('deleted_mail', existing) - kv.flush() - return 'success' - -@flask_blueprint.route('/mail/getinbox') -def list_inbox(): - return ','.join(loadinbox.load_inbox()) - - -@flask_blueprint.route('/mail/streaminbox') -def stream_inbox(): - def _stream(): - while True: - yield "data: " + ','.join(loadinbox.load_inbox()) + "\n\n" - sleep(1) - return sse_wrapper.handle_sse_request(_stream) - - -@flask_blueprint.route('/mail/getsentbox') -def list_sentbox(): - kv.refresh() - sentbox_list = sentboxdb.SentBox().listSent() - list_copy = list(sentbox_list) - deleted = kv.get('deleted_mail') - if deleted is None: - deleted = [] - for sent in list_copy: - if sent['hash'] in deleted: - sentbox_list.remove(sent) - continue - sent['name'] = contactmanager.ContactManager(sent['peer'], saveUser=False).get_info('name') - return json.dumps(sentbox_list) diff --git a/static-data/default-plugins/pms/main.py b/static-data/default-plugins/pms/main.py deleted file mode 100755 index 4d2219f2..00000000 --- a/static-data/default-plugins/pms/main.py +++ /dev/null @@ -1,87 +0,0 @@ -"""Onionr - Private P2P Communication. - -Private messages in an email like fashion -""" -import locale -import sys -import os - -import ujson as json - -from onionrusers import contactmanager -from utils import reconstructhash -from onionrutils import bytesconverter -import config -import notifier -""" - 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 . -""" - -locale.setlocale(locale.LC_ALL, '') - -plugin_name = 'pms' -PLUGIN_VERSION = '0.1.2' - -sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) -import sentboxdb, mailapi, loadinbox # import after path insert -from onblacklist import on_blacklist_add - -flask_blueprint = mailapi.flask_blueprint -security_whitelist = ['mail.mailstatic', 'mail.mailindex'] - - -def add_deleted(keyStore, b_hash): - existing = keyStore.get('deleted_mail') - bHash = reconstructhash.reconstruct_hash(b_hash) - if existing is None: - existing = [] - else: - if bHash in existing: - return - keyStore.put('deleted_mail', existing.append(b_hash)) - - -def on_insertblock(api, data={}): - meta = json.loads(data['meta']) - if meta['type'] == 'pm': - sentboxTools = sentboxdb.SentBox() - sentboxTools.addToSent(data['hash'], data['peer'], data['content'], meta['subject']) - - -def on_processblocks(api, data=None): - if data['type'] != 'pm': - return - notification_func = notifier.notify - data['block'].decrypt() - metadata = data['block'].bmetadata - - signer = bytesconverter.bytes_to_str(data['block'].signer) - user = contactmanager.ContactManager(signer, saveUser=False) - name = user.get_info("name") - if name != 'anonymous' and name != None: - signer = name.title() - else: - signer = signer[:5] - - - if data['block'].decrypted: - config.reload() - - if config.get('mail.notificationSound', True): - notification_func = notifier.notification_with_sound - if config.get('mail.notificationSetting', True): - if not config.get('mail.strangersNotification', True): - if not user.isFriend(): - return - notification_func(title="Onionr Mail - New Message", message="From: %s\n\nSubject: %s" % (signer, metadata['subject'])) diff --git a/static-data/default-plugins/pms/onblacklist.py b/static-data/default-plugins/pms/onblacklist.py deleted file mode 100644 index 0e521967..00000000 --- a/static-data/default-plugins/pms/onblacklist.py +++ /dev/null @@ -1,12 +0,0 @@ -from threading import Thread - -from onionrutils import localcommand - - -def on_blacklist_add(api, data=None): - blacklisted_data = data['data'] - - def remove(): - localcommand.local_command(f'/mail/deletemsg/{blacklisted_data}', post=True) - - Thread(target=remove).start() diff --git a/static-data/default-plugins/pms/sentboxdb.py b/static-data/default-plugins/pms/sentboxdb.py deleted file mode 100755 index b5d37330..00000000 --- a/static-data/default-plugins/pms/sentboxdb.py +++ /dev/null @@ -1,79 +0,0 @@ -""" - Onionr - Private P2P Communication - - This file handles the sentbox for the mail plugin -""" -import sqlite3 -import os -from onionrutils import epoch -from utils import identifyhome, reconstructhash -""" - 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 . -""" - - -class SentBox: - def __init__(self): - self.dbLocation = identifyhome.identify_home() + '/sentbox.db' - if not os.path.exists(self.dbLocation): - self.createDB() - return - - def connect(self): - self.conn = sqlite3.connect(self.dbLocation, timeout=30) - self.cursor = self.conn.cursor() - - def close(self): - self.conn.close() - - def createDB(self): - conn = sqlite3.connect(self.dbLocation) - cursor = conn.cursor() - cursor.execute("""CREATE TABLE sent( - hash id not null, - peer text not null, - message text not null, - subject text not null, - date int not null - ); - """) - conn.commit() - conn.close() - return - - def listSent(self): - self.connect() - retData = [] - for entry in self.cursor.execute('SELECT * FROM sent;'): - retData.append({'hash': entry[0], 'peer': entry[1], 'message': entry[2], 'subject': entry[3], 'date': entry[4]}) - self.close() - return retData - - def addToSent(self, blockID, peer, message, subject=''): - blockID = reconstructhash.deconstruct_hash(blockID) - self.connect() - args = (blockID, peer, message, subject, epoch.get_epoch()) - self.cursor.execute('INSERT INTO sent VALUES(?, ?, ?, ?, ?)', args) - self.conn.commit() - self.close() - return - - def removeSent(self, blockID): - blockID = reconstructhash.deconstruct_hash(blockID) - self.connect() - args = (blockID,) - self.cursor.execute('DELETE FROM sent where hash=?', args) - self.conn.commit() - self.close() - return diff --git a/static-data/default-plugins/pms/web/closesettings.js b/static-data/default-plugins/pms/web/closesettings.js deleted file mode 100644 index 5f91cc5b..00000000 --- a/static-data/default-plugins/pms/web/closesettings.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - Onionr - Private P2P Communication - - Settings modal closing - - 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 . -*/ - -document.getElementById('closeSettingsModalButton').onclick = function(){ - document.getElementById('settingsModal').classList.remove('is-active') - setActiveTab('inbox') -} - -document.querySelector("#settingsModal .modal-background").onclick = function(){ - document.getElementById('settingsModal').classList.remove('is-active') - setActiveTab('inbox') -} diff --git a/static-data/default-plugins/pms/web/index.html b/static-data/default-plugins/pms/web/index.html deleted file mode 100755 index c838d30b..00000000 --- a/static-data/default-plugins/pms/web/index.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - - - Onionr Mail - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

- Mail -

-

- Private and safe messages -

-
-
-
-
-

- - - -

-

- -

-

- -

-
-
-
-
-
-
-
- -
-
-
- -
- From: Signature: -
-
- Subject: -
-
- -
-
-
-
-
-
-
-
- - To: -
-
-
-
- - - -
- -
No messages to show ¯\_(ツ)_/¯
-
-
- API server either shutdown, has disabled mail, or has experienced a bug. -
-
-
Nothing here yet 😞
-
-
-
-
-
-
- -
-
-
- To: -
- Subject: -
- -
- -
-
-
-
-
- - - \ No newline at end of file diff --git a/static-data/default-plugins/pms/web/loadsettings.js b/static-data/default-plugins/pms/web/loadsettings.js deleted file mode 100644 index 3ec81891..00000000 --- a/static-data/default-plugins/pms/web/loadsettings.js +++ /dev/null @@ -1,29 +0,0 @@ -mailSettings = {} - -fetch('/config/get/mail', { - headers: { - "content-type": "application/json", - "token": webpass - }}) -.then((resp) => resp.json()) -.then(function(settings) { - mailSettings = settings || {} - if (mailSettings.default_forward_secrecy === false){ - document.getElementById('forwardSecrecySetting').checked = false - } - if (mailSettings.use_padding === false){ - document.getElementById('messagePaddingSetting').checked = false - } - if (mailSettings.notificationSetting === false){ - document.getElementById('notificationSetting').checked = false - } - if (mailSettings.notificationSound === false){ - document.getElementById('notificationSound').checked = false - } - if (typeof mailSettings.signature != undefined && mailSettings.signature != null && mailSettings.signature != ""){ - document.getElementById('mailSignatureSetting').value = mailSettings.signature - } - if (mailSettings.strangersNotification == false){ - document.getElementById('strangersNotification').checked = false - } - }) \ No newline at end of file diff --git a/static-data/default-plugins/pms/web/mail.css b/static-data/default-plugins/pms/web/mail.css deleted file mode 100755 index f2212a04..00000000 --- a/static-data/default-plugins/pms/web/mail.css +++ /dev/null @@ -1,60 +0,0 @@ -.threadEntry button{ - margin-right: 1%; -} -.threadEntry span, .sentboxList span{ - padding-left: 1%; -} -.threadEntry, .sentboxList{ - cursor: pointer; -} - -.overlayContent{ - background-color: lightgray; - border: 3px solid black; - border-radius: 3px; - color: black; - font-family: Verdana, Geneva, Tahoma, sans-serif; - min-height: 100%; - padding: 1em; - margin: 1em; -} - -#draftText{ - margin-top: 1em; - margin-bottom: 1em; - display: block; - width: 50%; - height: 75%; - min-width: 2%; - min-height: 5%; - background: white; - color: black; -} - -.sentboxList{ - padding-top: 1em; -} - -.messageContent{ - padding-top: 1em; -} - - -#tabBtns ul .icon { - pointer-events: none; -} - - -#settingsModal .modal-card-body{ - font-size: 150%; - min-height: 300px; -} - -#settingsModal textarea{ - resize: none; - margin-top: 1em; -} - -#settingsModal small{ - font-size: 0.5em; -} diff --git a/static-data/default-plugins/pms/web/mail.js b/static-data/default-plugins/pms/web/mail.js deleted file mode 100755 index 8153c817..00000000 --- a/static-data/default-plugins/pms/web/mail.js +++ /dev/null @@ -1,467 +0,0 @@ -/* - Onionr - Private P2P Communication - - This file handles the mail interface - - 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 . -*/ - -pms = '' -sentbox = '' -threadPart = document.getElementById('threads') -threadPlaceholder = document.getElementById('threadPlaceholder') -tabBtns = document.getElementById('tabBtns') -threadContent = {} -replyBtn = document.getElementById('replyBtn') -addUnknownContact = document.getElementById('addUnknownContact') -noInbox = document.getElementById('noInbox') -humanReadableCache = {} - -function stripEndZeroes(str){ - str = str.split("") - let zeroCount = 0 - for (x = str.length - 1; x != 0; x--){ - if (str[x] == "0"){ - zeroCount += 1 - } - else{ - break - } - } - str.splice(str.length - zeroCount, zeroCount) - str = str.join("") - return str -} - -async function addContact(pubkey, friendName){ - fetch('/friends/add/' + pubkey, { - method: 'POST', - headers: { - "token": webpass - }}).then(function(data) { - if (friendName.trim().length > 0){ - post_to_url('/friends/setinfo/' + pubkey + '/name', {'data': friendName, 'token': webpass}) - } - }) -} - -function openReply(bHash, quote, subject){ - var inbox = document.getElementsByClassName('threadEntry') - var entry = '' - var friendName = '' - var key = '' - for(var i = 0; i < inbox.length; i++) { - if (inbox[i].getAttribute('data-hash') === bHash){ - entry = inbox[i] - } - } - if (entry.getAttribute('data-nameset') == 'true'){ - document.getElementById('friendSelect').value = document.getElementById('fromUser').value - } - key = entry.getAttribute('data-pubkey') - document.getElementById('draftID').value = key - document.getElementById('draftSubject').value = 'RE: ' + subject - - // Add quoted reply - var splitQuotes = quote.split('\n') - for (var x = 0; x < splitQuotes.length; x++){ - splitQuotes[x] = '> ' + splitQuotes[x] - } - - if (typeof humanReadableCache[key] != 'undefined'){ - document.getElementById('draftID').value = humanReadableCache[key] - quote = '\n' + humanReadableCache[key].split('-').slice(0,3).join('-') + ' wrote:\n' + splitQuotes.join('\n') - } - else{ - quote = '\n' + key.substring(0, 12) + ' wrote:' + '\n' + splitQuotes.join('\n') - } - document.getElementById('draftText').value = quote - setActiveTab('compose') -} - -function openThread(bHash, sender, date, sigBool, pubkey, subjectLine){ - addUnknownContact.style.display = 'none' - var messageDisplay = document.getElementById('threadDisplay') - - fetch('/getblockbody/' + bHash, { - "method": "get", - headers: { - "token": webpass - }}) - .then((resp) => resp.text()) - .then(function(resp) { - document.getElementById('fromUser').value = sender || 'Anonymous' - document.getElementById('fromUser').value = pubkey || '' - document.getElementById('subjectView').innerText = subjectLine - - resp = stripEndZeroes(resp) - - messageDisplay.innerText = resp - var sigEl = document.getElementById('sigValid') - var sigMsg = 'signature' - - // show add unknown contact button if peer is unknown - if (sender !== myPub && sigBool){ - addUnknownContact.style.display = 'inline' - } - - if (sigBool){ - sigMsg = 'Good ' + sigMsg - sigEl.classList.remove('danger') - } - else{ - sigMsg = 'Bad/no ' + sigMsg + ' (message could be impersonating someone)' - sigEl.classList.add('danger') - replyBtn.style.display = 'none' - } - sigEl.innerText = sigMsg - overlay('messageDisplay') - replyBtn.onclick = function(){ - document.getElementById('messageDisplay').style.visibility = 'hidden' - openReply(bHash, messageDisplay.innerText, subjectLine) - } - addUnknownContact.onclick = function(){ - var friendName = prompt("Enter an alias for this contact:") - if (friendName === null || friendName.length == 0){ - return - } - addContact(pubkey, friendName) - } - }) -} - -function setActiveTab(tabName){ - threadPart.innerHTML = "" - noInbox.style.display = 'none' - window.inboxActive = false - document.getElementById('sendMessage').classList.add('is-hidden') - switch(tabName){ - case 'inbox': - window.inboxActive = true - refreshPms() - getInbox() - break - case 'sent': - getSentbox() - break - case 'compose': - document.getElementById('sendMessage').classList.remove('is-hidden') - break - case 'settings': - document.getElementById('settingsModal').classList.add('is-active') - break - } -} - -function deleteMessage(bHash){ - fetch('/mail/deletemsg/' + bHash, { - "method": "post", - headers: { - "token": webpass - }}) -} - -function mailPing(){ - fetch('/mail/ping', { - "method": "get", - headers: { - "token": webpass - }}) - .then(function(resp) { - var pings = document.getElementsByClassName('mailPing') - if (resp.ok){ - for (var i=0; i < pings.length; i++){ - pings[i].style.display = 'none'; - } - } - else{ - for (var i=0; i < pings.length; i++){ - pings[i].style.display = 'block'; - } - } - }) -} - -function loadInboxEntries(bHash){ - fetch('/getblockheader/' + bHash, { - headers: { - "token": webpass - }}) - .then((resp) => resp.json()) // Transform the data into json - .then(function(resp) { - //console.log(resp) - var entry = document.createElement('div') - var bHashDisplay = document.createElement('span') - //var senderInput = document.createElement('input') - var senderInput = document.createElement('span') - var subjectLine = document.createElement('span') - var dateStr = document.createElement('span') - var validSig = document.createElement('span') - var deleteBtn = document.createElement('button') - var humanDate = new Date(0) - var metadata = resp['metadata'] - humanDate.setUTCSeconds(resp['meta']['time']) - humanDate = humanDate.toString() - validSig.style.display = 'none' - - if (typeof resp['meta']['signer'] != 'undefined' && resp['meta']['signer'] != ''){ - fetch('/friends/getinfo/' + resp['meta']['signer'] + '/name', { - headers: { - "token": webpass - }}) - .then(function(resp2){ - if (!resp2.ok){ - setHumanReadableValue(senderInput, resp['meta']['signer']) - entry.setAttribute('data-nameSet', false) - } - else{ - resp2.text().then(function(resp2){ - loadHumanReadableToCache(resp['meta']['signer']) - senderInput.innerText = resp2 - entry.setAttribute('data-nameSet', true) - }) - } - }) - - } - else{ - senderInput.innerText = 'Anonymous' - entry.setAttribute('data-nameSet', false) - } - if (! resp['meta']['validSig']){ - validSig.style.display = 'inline' - validSig.innerText = 'Signature Validity: Bad' - validSig.style.color = 'red' - } - //bHashDisplay.innerText = bHash.substring(0, 10) - entry.setAttribute('data-hash', bHash) - entry.setAttribute('data-pubkey', resp['meta']['signer']) - senderInput.readOnly = true - dateStr.innerText = humanDate.substring(0, humanDate.indexOf('(')) - deleteBtn.classList.add('delete', 'deleteBtn') - if (metadata['subject'] === undefined || metadata['subject'] === null) { - subjectLine.innerText = '()' - } - else{ - subjectLine.innerText = '(' + metadata['subject'] + ')' - } - //entry.innerHTML = 'sender ' + resp['meta']['signer'] + ' - ' + resp['meta']['time'] - threadPart.appendChild(entry) - entry.appendChild(deleteBtn) - entry.appendChild(bHashDisplay) - entry.appendChild(senderInput) - entry.appendChild(subjectLine) - entry.appendChild(dateStr) - entry.appendChild(validSig) - entry.classList.add('threadEntry') - - entry.onclick = function(event){ - if (event.target.classList.contains('deleteBtn')){ - return - } - openThread(entry.getAttribute('data-hash'), senderInput.innerText, dateStr.innerText, resp['meta']['validSig'], entry.getAttribute('data-pubkey'), subjectLine.innerText) - } - - deleteBtn.onclick = function(){ - entry.parentNode.removeChild(entry); - deleteMessage(entry.getAttribute('data-hash')) - } - - }.bind(bHash)) -} - -function getInbox(){ - if (! window.inboxActive){ - return - } - var els = document.getElementsByClassName('threadEntry') - var showed = false - for(var i = 0; i < pms.length; i++) { - var add = true - if (pms[i].trim().length == 0){ - noInbox.style.display = 'block' - continue - } - else{ - threadPlaceholder.style.display = 'none' - showed = true - } - for (var x = 0; x < els.length; x++){ - if (pms[i] === els[x].getAttribute('data-hash')){ - add = false - } - } - if (add && window.inboxActive) { - loadInboxEntries(pms[i]) - } - } - if (! showed){ - threadPlaceholder.style.display = 'block' - } -} - -function getSentbox(){ - fetch('/mail/getsentbox', { - headers: { - "token": webpass - }}) - .then((resp) => resp.json()) // Transform the data into json - .then(function(resp) { - var keys = []; - var entry = document.createElement('div') - for(var k in resp) keys.push(k); - if (keys.length == 0){ - threadPart.innerHTML = "nothing to show here yet." - } - for (var i = keys.length - 1; i > -1; i--) (function(i, resp){ - var entry = document.createElement('div') - var toLabel = document.createElement('span') - toLabel.innerText = 'To: ' - var toEl = document.createElement('span') - toEl.classList.add('toElement') - var sentDate = document.createElement('span') - var humanDate = new Date(0) - humanDate.setUTCSeconds(resp[i]['date']) - humanDate = humanDate.toString() - var preview = document.createElement('span') - var deleteBtn = document.createElement('button') - var message = resp[i]['message'] - deleteBtn.classList.add('deleteBtn', 'delete') - - sentDate.innerText = humanDate.substring(0, humanDate.indexOf('(')) - if (resp[i]['name'] == null || resp[i]['name'].toLowerCase() == 'anonymous'){ - toEl.innerText = resp[i]['peer'] - setHumanReadableValue(toEl, resp[i]['peer']) - } - else{ - toEl.innerText = resp[i]['name'] - } - preview.innerText = '(' + resp[i]['subject'] + ')' - entry.classList.add('sentboxList') - entry.setAttribute('data-hash', resp[i]['hash']) - entry.appendChild(deleteBtn) - entry.appendChild(toLabel) - entry.appendChild(toEl) - entry.appendChild(preview) - entry.appendChild(sentDate) - - threadPart.appendChild(entry) - - entry.onclick = function(e){ - if (e.target.classList.contains('deleteBtn')){ - deleteMessage(e.target.parentNode.getAttribute('data-hash')) - e.target.parentNode.parentNode.removeChild(e.target.parentNode) - return - } - showSentboxWindow(toEl.innerText, message) - } - })(i, resp) - threadPart.appendChild(entry) - }.bind(threadPart)) -} - -function showSentboxWindow(to, content){ - content = stripEndZeroes(content) - document.getElementById('toID').value = to - document.getElementById('sentboxDisplayText').innerText = content - overlay('sentboxDisplay') -} - -function refreshPms(callNext){ - if (! window.inboxActive){ - return - } - if (document.hidden){ - return - } -fetch('/mail/getinbox', { - headers: { - "token": webpass - }}) -.then((resp) => resp.text()) -.then(function(data) { - pms = data.split(',') - if (pms.length > 0){ - noInbox.style.display = 'none' - } - if (callNext){ - getInbox() - } - }) -} - -tabBtns.onclick = function(event){ - var children = tabBtns.children[0].children - for (var i = 0; i < children.length; i++) { - var btn = children[i] - btn.classList.remove('is-active') - } - event.target.parentElement.parentElement.classList.add('is-active') - setActiveTab(event.target.innerText.toLowerCase()) -} - -for (var i = 0; i < document.getElementsByClassName('refresh').length; i++){ - document.getElementsByClassName('refresh')[i].style.float = 'right' -} - -fetch('/friends/list', { - headers: { - "token": webpass - }}) -.then((resp) => resp.json()) // Transform the data into json -.then(function(resp) { - var friendSelectParent = document.getElementById('friendSelect') - var keys = []; - for(var k in resp) keys.push(k); - - friendSelectParent.appendChild(document.createElement('option')) - for (var i = 0; i < keys.length; i++) { - var option = document.createElement("option") - var name = resp[keys[i]]['name'] || "" - option.value = keys[i] - if (name.length == 0){ - option.text = keys[i] - } - else{ - option.text = name - } - friendSelectParent.appendChild(option) - } -}) -setActiveTab('inbox') - -setInterval(function(){mailPing()}, 10000) -mailPing() -window.inboxInterval = setInterval(function(){refreshPms(true)}, 3000) -refreshPms(true) - -document.addEventListener("visibilitychange", function() { - if (document.visibilityState === 'visible') { - refreshPms() - } - }) - -/* -let mailStream = function(){ - var streamSource = new EventSourcePolyfill('/mail/streaminbox', { - headers: { - "token": webpass - } - }) - streamSource.onmessage = function(e){ - console.debug(e.data) - } -} -mailStream() -*/ \ No newline at end of file diff --git a/static-data/default-plugins/pms/web/sendmail.js b/static-data/default-plugins/pms/web/sendmail.js deleted file mode 100755 index dd7c44ff..00000000 --- a/static-data/default-plugins/pms/web/sendmail.js +++ /dev/null @@ -1,109 +0,0 @@ -/* - Onionr - Private P2P Communication - - This file handles the mail interface - - 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 . -*/ - -var sendbutton = document.getElementById('sendMail') -messageContent = document.getElementById('draftText') -to = document.getElementById('draftID') -subject = document.getElementById('draftSubject') -friendPicker = document.getElementById('friendSelect') - -function utf8Length(s) { - var size = encodeURIComponent(s).match(/%[89ABab]/g); - return s.length + (size ? size.length : 0); - } - -function padString(string_data, round_nearest_byte_exponent = 3){ - if (utf8Length(string_data) === 0){ - string_data += '0' - } - let round_size = 10 ** round_nearest_byte_exponent - while (utf8Length(string_data) % round_size > 0){ - string_data += '0' - } - return string_data -} - -function sendMail(toData, message, subject){ - let meta = {'subject': subject} - - if (document.getElementById('messagePaddingSetting').checked){ - message = padString(message) - } - - if (document.getElementById('mailSignatureSetting').value !== false){ - message += "\n" - message += document.getElementById('mailSignatureSetting').value - } - - postData = {'message': message, 'to': toData, 'type': 'pm', 'encrypt': true, 'meta': JSON.stringify(meta)} - postData.forward = document.getElementById('forwardSecrecySetting').checked - postData = JSON.stringify(postData) - sendForm.style.display = 'none' - - fetch('/insertblock', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}).then(function(resp){ - if (!resp.ok){ - PNotify.error({ - text: 'Malformed input' - }) - sendForm.style.display = 'block' - throw new Error("Malformed input in sendmail") - } - return resp - }) - .then((resp) => resp.text()) // Transform the data into text - .then(function(data) { - sendForm.style.display = 'block' - PNotify.success({ - text: 'Queued for sending!', - delay: 3500, - mouseReset: false - }) - to.value = subject.value = messageContent.value = "" - friendPicker.value = "" - subject.value = "" - }) -} - -var friendPicker = document.getElementById('friendSelect') -friendPicker.onchange = function(){ - to.value = friendPicker.value -} - -sendForm.onsubmit = function(){ - let getInstances = function(string, word) { - return string.split(word).length - 1; - } - - if(getInstances(to.value, '-') != 15){ - if (to.value.length != 56 && to.value.length != 52){ - PNotify.error({ - text: 'User ID is not valid' - }) - return false - } - } - sendMail(to.value, messageContent.value, subject.value) - return false -} diff --git a/static-data/default-plugins/pms/web/sethumanreadable.js b/static-data/default-plugins/pms/web/sethumanreadable.js deleted file mode 100644 index 6a4df08d..00000000 --- a/static-data/default-plugins/pms/web/sethumanreadable.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - Onionr - Private P2P Communication - - Load human readable public keys into a cache - - 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 . -*/ -function loadHumanReadableToCache(key){ - fetch('/getHumanReadable/' + key, { - headers: { - "token": webpass - }}) - .then((resp) => resp.text()) - .then(function(resp) { - humanReadableCache[key] = resp - }) -} - -function setHumanReadableValue(el, key){ - if (typeof humanReadableCache[key] != 'undefined'){ - el.innerText = humanReadableCache[key].split('-').slice(0,3).join('-') - return - } - else{ - loadHumanReadableToCache(key) - setTimeout(function(){setHumanReadableValue(el, key)}, 100) - return - } -} \ No newline at end of file diff --git a/static-data/default-plugins/pms/web/settings.js b/static-data/default-plugins/pms/web/settings.js deleted file mode 100644 index f410660d..00000000 --- a/static-data/default-plugins/pms/web/settings.js +++ /dev/null @@ -1,120 +0,0 @@ -/* - Onionr - Private P2P Communication - - Handle mail settings - - 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 . -*/ -var notificationSetting = document.getElementById('notificationSetting') -var friendOnlyNotification = document.getElementById('strangersNotification') -var notificationSound = document.getElementById('notificationSound') -var sigSetting = document.getElementById('mailSignatureSetting') - -document.getElementById('forwardSecrecySetting').onchange = function(e){ - postData = JSON.stringify({"default_forward_secrecy": e.target.checked}) - fetch('/config/set/mail', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}) - .then((resp) => resp.text()) - .then(function(data) { - mailSettings['forwardSecrecy'] = document.getElementById('forwardSecrecySetting').checked - PNotify.success({ - text: 'Successfully toggled default forward secrecy' - }) - }) -} - -notificationSound.onchange = function(e){ - var postData = JSON.stringify({"notificationSound": e.target.checked}) - fetch('/config/set/mail', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}) - .then(function(data) { - mailSettings['notificationSound'] = notificationSound.checked - PNotify.success({ - text: 'Successfully notification sound' - }) - }) -} - -friendOnlyNotification.onchange = function(e){ - var postData = JSON.stringify({"strangersNotification": e.target.checked}) - fetch('/config/set/mail', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}) - .then(function(data) { - mailSettings['strangersNotification'] = friendOnlyNotification.checked - PNotify.success({ - text: 'Successfully toggled notifications from strangers' - }) - }) -} - - -notificationSetting.onchange = function(e){ - var notificationSettings = document.getElementsByClassName('notificationSetting') - if (e.target.checked){ - for (i = 0; i < notificationSettings.length; i++){ - notificationSettings[i].style.display = "flex" - } - } - else{ - for (i = 0; i < notificationSettings.length; i++){ - notificationSettings[i].style.display = "none" - } - } - var postData = JSON.stringify({"notificationSetting": e.target.checked}) - fetch('/config/set/mail', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}) - .then(function(data) { - mailSettings['notificationSetting'] = notificationSetting.checked - PNotify.success({ - text: 'Successfully toggled default mail notifications' - }) - }) -} - -sigSetting.onchange = function(){ - var postData = JSON.stringify({"signature": sigSetting.value}) - fetch('/config/set/mail', { - method: 'POST', - body: postData, - headers: { - "content-type": "application/json", - "token": webpass - }}) - .then(function(data) { - mailSettings['signature'] = sigSetting.value - PNotify.success({ - text: 'Set mail signature' - }) - }) -} \ No newline at end of file