diff --git a/src/apiservers/__init__.py b/src/apiservers/__init__.py index c7c693ba..7c801db6 100755 --- a/src/apiservers/__init__.py +++ b/src/apiservers/__init__.py @@ -1,3 +1,10 @@ +"""Flask WSGI apps for the public and private API servers + +Public is net-facing server meant for other nodes +Private is meant for controlling and accessing this node +""" + from . import public, private + PublicAPI = public.PublicAPI -ClientAPI = private.PrivateAPI \ No newline at end of file +ClientAPI = private.PrivateAPI diff --git a/src/apiservers/private/__init__.py b/src/apiservers/private/__init__.py index ca7587df..af80be37 100644 --- a/src/apiservers/private/__init__.py +++ b/src/apiservers/private/__init__.py @@ -3,6 +3,21 @@ This file handles all incoming http requests to the client, using Flask ''' +import base64 +import os + +import flask +from gevent.pywsgi import WSGIServer + +from onionrutils import epoch +import httpapi +from filepaths import private_API_host_file +import logger + +from etc import waitforsetvar +from . import register_private_blueprints +import config +from .. import public ''' 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 @@ -17,39 +32,33 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import base64, os, time -import flask -from gevent.pywsgi import WSGIServer -from onionrutils import epoch -import httpapi, filepaths, logger -from . import register_private_blueprints -from etc import waitforsetvar -import serializeddata, config -from .. import public + + class PrivateAPI: ''' Client HTTP api ''' - callbacks = {'public' : {}, 'private' : {}} + callbacks = {'public': {}, 'private': {}} def __init__(self): ''' Initialize the api server, preping variables for later use - This initialization defines all of the API entry points and handlers for the endpoints and errors + This initialization defines all of the API entry points + and handlers for the endpoints and errors This also saves the used host (random localhost IP address) to the data folder in host.txt ''' self.config = config + self.startTime = epoch.get_epoch() app = flask.Flask(__name__) - bindPort = int(config.get('client.client.port', 59496)) - self.bindPort = bindPort + bind_port = int(config.get('client.client.port', 59496)) + self.bindPort = bind_port self.clientToken = config.get('client.webpassword') - self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() - self.host = httpapi.apiutils.setbindip.set_bind_IP(filepaths.private_API_host_file) + self.host = httpapi.apiutils.setbindip.set_bind_IP(private_API_host_file) logger.info('Running api on %s:%s' % (self.host, self.bindPort)) self.httpServer = '' @@ -58,7 +67,7 @@ class PrivateAPI: register_private_blueprints.register_private_blueprints(self, app) httpapi.load_plugin_blueprints(app) self.app = app - + def start(self): waitforsetvar.wait_for_set_var(self, "_too_many") self.publicAPI = self._too_many.get(public.PublicAPI) diff --git a/src/communicatorutils/downloadblocks/__init__.py b/src/communicatorutils/downloadblocks/__init__.py index 87ea6c9c..1291d988 100755 --- a/src/communicatorutils/downloadblocks/__init__.py +++ b/src/communicatorutils/downloadblocks/__init__.py @@ -3,6 +3,20 @@ Download blocks using the communicator instance ''' +import onionrexceptions +import logger +import onionrpeers +import communicator +from communicator import peeraction +from communicator import onlinepeers +from onionrutils import blockmetadata +from onionrutils import validatemetadata +from coredb import blockmetadb +import onionrcrypto +import onionrstorage +from onionrblocks import onionrblacklist +from onionrblocks import storagecounter +from . import shoulddownload ''' 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 @@ -17,17 +31,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import communicator, onionrexceptions -import logger, onionrpeers -from onionrutils import blockmetadata, stringvalidators, validatemetadata -from coredb import blockmetadb -from . import shoulddownload -from communicator import peeraction, onlinepeers -import onionrcrypto, onionrstorage -from onionrblocks import onionrblacklist, storagecounter -def download_blocks_from_communicator(comm_inst): - '''Use Onionr communicator instance to download blocks in the communicator's queue''' - assert isinstance(comm_inst, communicator.OnionrCommunicatorDaemon) + + +def download_blocks_from_communicator(comm_inst: "OnionrCommunicatorDaemon"): + '''Use communicator instance to download blocks in the comms's queue''' blacklist = onionrblacklist.OnionrBlackList() storage_counter = storagecounter.StorageCounter() LOG_SKIP_COUNT = 50 # for how many iterations we skip logging the counter @@ -53,7 +60,6 @@ def download_blocks_from_communicator(comm_inst): break # Do not download blocks being downloaded if blockHash in comm_inst.currentDownloading: - #logger.debug('Already downloading block %s...' % blockHash) continue comm_inst.currentDownloading.append(blockHash) # So we can avoid concurrent downloading in other threads of same block @@ -130,4 +136,4 @@ def download_blocks_from_communicator(comm_inst): except KeyError: pass comm_inst.currentDownloading.remove(blockHash) - comm_inst.decrementThreadCount('getBlocks') \ No newline at end of file + comm_inst.decrementThreadCount('getBlocks') diff --git a/src/config.py b/src/config/__init__.py similarity index 100% rename from src/config.py rename to src/config/__init__.py diff --git a/src/config/onboarding.py b/src/config/onboarding.py new file mode 100644 index 00000000..66141196 --- /dev/null +++ b/src/config/onboarding.py @@ -0,0 +1,34 @@ +""" + Onionr - Private P2P Communication + + Setup config from onboarding choices +""" +from pathlib import Path + +from filepaths import onboarding_mark_file +import onionrtypes +""" + 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 set_config_from_onboarding(config_settings: onionrtypes.OnboardingConfig): + return + +def set_onboarding_finished(): + """Create the onboarding completed setting file""" + Path(onboarding_mark_file).touch() + +def is_onboarding_finished() -> bool: + return True diff --git a/src/filepaths/__init__.py b/src/filepaths/__init__.py index f65a287e..0942f7a2 100644 --- a/src/filepaths/__init__.py +++ b/src/filepaths/__init__.py @@ -28,4 +28,6 @@ run_check_file = home + '.runcheck' data_nonce_file = home + 'block-nonces.dat' -keys_file = home + 'keys.txt' \ No newline at end of file +keys_file = home + 'keys.txt' + +onboarding_mark_file = home + 'onboarding-completed' diff --git a/src/httpapi/miscpublicapi/upload.py b/src/httpapi/miscpublicapi/upload.py index eaf96b1a..9977f7bb 100755 --- a/src/httpapi/miscpublicapi/upload.py +++ b/src/httpapi/miscpublicapi/upload.py @@ -3,6 +3,14 @@ Accept block uploads to the public API server ''' +import sys +from flask import Response +from flask import abort + +from onionrblocks import blockimporter +import onionrexceptions +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 @@ -17,18 +25,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import sys -from flask import Response, abort -from onionrblocks import blockimporter -import onionrexceptions, logger def accept_upload(request): + """Accept uploaded blocks to our public Onionr protocol API server""" resp = 'failure' data = request.get_data() if sys.getsizeof(data) < 100000000: try: - if blockimporter.importBlockFromData(data): + if blockimporter.import_block_from_data(data): resp = 'success' else: resp = 'failure' diff --git a/src/onionrblocks/blockimporter.py b/src/onionrblocks/blockimporter.py index dec7c75a..e3552847 100755 --- a/src/onionrblocks/blockimporter.py +++ b/src/onionrblocks/blockimporter.py @@ -3,6 +3,17 @@ Import block data and save it ''' +from onionrexceptions import BlacklistedBlock +from onionrexceptions import DiskAllocationReached +from onionrexceptions import InvalidProof +import logger +from onionrutils import validatemetadata +from onionrutils import blockmetadata +from coredb import blockmetadb +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 @@ -17,39 +28,41 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import onionrexceptions, logger -from onionrutils import validatemetadata, blockmetadata -from coredb import blockmetadb -from . import onionrblacklist -import onionrstorage -import onionrcrypto as crypto -def importBlockFromData(content): + + +def import_block_from_data(content): blacklist = onionrblacklist.OnionrBlackList() - retData = False + ret_data = False try: content = content.encode() except AttributeError: pass - dataHash = crypto.hashers.sha3_hash(content) + data_hash = crypto.hashers.sha3_hash(content) - if blacklist.inBlacklist(dataHash): - raise onionrexceptions.BlacklistedBlock('%s is a blacklisted block' % (dataHash,)) + if blacklist.inBlacklist(data_hash): + raise BlacklistedBlock(f'%s is a blacklisted block {data_hash}') - metas = blockmetadata.get_block_metadata_from_data(content) # returns tuple(metadata, meta), meta is also in metadata + # returns tuple(metadata, meta), meta is also in metadata + metas = blockmetadata.get_block_metadata_from_data(content) metadata = metas[0] - if validatemetadata.validate_metadata(metadata, metas[2]): # check if metadata is valid - if crypto.cryptoutils.verify_POW(content): # check if POW is enough/correct - logger.info('Imported block passed proof, saving.', terminal=True) + + # 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: blockHash = onionrstorage.set_data(content) - except onionrexceptions.DiskAllocationReached: + except DiskAllocationReached: logger.warn('Failed to save block due to full disk allocation') else: blockmetadb.add_to_block_DB(blockHash, dataSaved=True) - blockmetadata.process_block_metadata(blockHash) # caches block metadata values to block database - retData = True + # caches block metadata values to block database + blockmetadata.process_block_metadata(blockHash) + ret_data = True else: - raise onionrexceptions.InvalidProof - return retData \ No newline at end of file + raise InvalidProof + return ret_data diff --git a/src/onionrtypes/__init__.py b/src/onionrtypes/__init__.py index 74585249..7b881270 100644 --- a/src/onionrtypes/__init__.py +++ b/src/onionrtypes/__init__.py @@ -6,3 +6,5 @@ UserIDSecretKey = NewType('UserIDSecretKey', str) DeterministicKeyPassphrase = NewType('DeterministicKeyPassphrase', str) BlockHash = NewType('BlockHash', str) + +OnboardingConfig = NewType('OnboardingConfig', str) diff --git a/static-data/www/onboarding/donate-modal.css b/static-data/www/onboarding/donate-modal.css new file mode 100644 index 00000000..6336eb98 --- /dev/null +++ b/static-data/www/onboarding/donate-modal.css @@ -0,0 +1,13 @@ +.donateHeader{ + font-size: 2em; +} + +.donateFinished{ + display: block; + margin-top: 1em; +} + +.donateBody p{ + padding-top: 1em; + text-align: justify; +} \ No newline at end of file diff --git a/static-data/www/onboarding/donate-modal.html b/static-data/www/onboarding/donate-modal.html new file mode 100644 index 00000000..0ccad02d --- /dev/null +++ b/static-data/www/onboarding/donate-modal.html @@ -0,0 +1,17 @@ +Donate + +

+ +

Onionr is a volunteer-driven project, and infrastructure is paid for out of pocket. +

+

+ Please donate the price of a cup of coffee to sustain development. +

+ +
+ +Paypal/Card: Ko-fi +
+Bitcoin: 1onion55FXzm6h8KQw3zFw2igpHcV7LPq + + diff --git a/static-data/www/onboarding/donate.js b/static-data/www/onboarding/donate.js new file mode 100644 index 00000000..17f37db0 --- /dev/null +++ b/static-data/www/onboarding/donate.js @@ -0,0 +1,45 @@ +/* + Onionr - Private P2P Communication + + Handles onboarding donations for Onionr + + 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 +*/ + + +let donateFinishedButtons = document.getElementsByClassName('donateFinished') +configInfo = {} + +let openDonateModal = function(newConfigInfo){ + fetch('donate-modal.html') + .then((resp) => resp.text()) + .then(function(resp) { + document.getElementsByClassName('donateModal')[0].classList.add('is-active') + + // Load the donate modal html and display it + let donateBody = document.getElementsByClassName('donateBody')[0] + + donateBody.innerHTML = resp + + let donateFinishedButton = document.getElementsByClassName('donateFinished')[0] + + for (i = 0; i < donateFinishedButtons.length; i++){ + donateFinishedButtons[i].onclick = function(){ + document.getElementsByClassName('donateModal')[0].classList.remove('is-active') + sendConfig(configInfo) + } + } + + }) +} diff --git a/static-data/www/onboarding/index.html b/static-data/www/onboarding/index.html index fcf54ae1..2f79d1ed 100644 --- a/static-data/www/onboarding/index.html +++ b/static-data/www/onboarding/index.html @@ -12,11 +12,13 @@ + + @@ -65,8 +67,20 @@
+ +
- +

Welcome. There are just a few questions for you to answer before you get started.


@@ -94,11 +108,13 @@
I want to...
- +

+
+
diff --git a/static-data/www/onboarding/onboarding.js b/static-data/www/onboarding/onboarding.js index 4549a2bc..5e60e5a8 100644 --- a/static-data/www/onboarding/onboarding.js +++ b/static-data/www/onboarding/onboarding.js @@ -16,11 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ + fetch('/getnewkeys', { headers: { "token": webpass }}) - .then((resp) => resp.text()) // Transform the data into text + .then((resp) => resp.text()) .then(function(resp) { keys = resp.split('') }) @@ -29,6 +30,19 @@ function getCheckValue(elName){ return document.getElementsByName(elName)[0].checked } +function sendConfig(configInfo){ + fetch('/setonboarding', { + method: 'POST', + headers: { + "token": webpass, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({configInfo}) + }).then(function(data) { + }) +} + + document.getElementById('onboardingForm').onsubmit = function(e){ submitInfo = {} submitInfo.massSurveil = getCheckValue('state') @@ -39,6 +53,14 @@ document.getElementById('onboardingForm').onsubmit = function(e){ submitInfo.donate = getCheckValue('donate') submitInfo.deterministic = getCheckValue('useDeterministic') submitInfo.mail = getCheckValue('useMail') + submitInfo.circles = getCheckValue('useCircles') + + if (submitInfo.donate){ + openDonateModal(submitInfo) + return false + } + + sendConfig(submitInfo) e.preventDefault() } \ No newline at end of file diff --git a/static-data/www/shared/about.html b/static-data/www/shared/about.html index 0bd1e82b..d3e3fa68 100644 --- a/static-data/www/shared/about.html +++ b/static-data/www/shared/about.html @@ -13,7 +13,7 @@ Contributors: diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 00000000..dd1beac5 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,16 @@ +import sys, os +sys.path.append(".") +sys.path.append("src/") +import unittest, uuid, json +TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/' +print("Test directory:", TEST_DIR) +os.environ["ONIONR_HOME"] = TEST_DIR +import onionrblocks +from utils import createdirs +from utils import readstatic +createdirs.create_dirs() +class OnionrConfigTest(unittest.TestCase): + def test_security_value(self): + return + +unittest.main()