diff --git a/onionr/api.py b/onionr/api.py index b43908e1..0f83a4de 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -68,6 +68,8 @@ class API: self.clientToken = config.get('client')['client_hmac'] self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() + self.mimeType = 'text/plain' + with open('data/time-bypass.txt', 'w') as bypass: bypass.write(self.timeBypassToken) @@ -96,12 +98,17 @@ class API: def afterReq(resp): if not self.requestFailed: resp.headers['Access-Control-Allow-Origin'] = '*' - else: - resp.headers['server'] = 'Onionr' - resp.headers['Content-Type'] = 'text/plain' - resp.headers["Content-Security-Policy"] = "default-src 'none'" + #else: + # resp.headers['server'] = 'Onionr' + resp.headers['Content-Type'] = self.mimeType + resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'" resp.headers['X-Frame-Options'] = 'deny' resp.headers['X-Content-Type-Options'] = "nosniff" + resp.headers['server'] = 'Onionr' + + # reset to text/plain to help prevent browser attacks + if self.mimeType != 'text/plain': + self.mimeType = 'text/plain' return resp @@ -111,6 +118,11 @@ class API: timingToken = '' else: timingToken = request.args.get('timingToken') + data = request.args.get('data') + try: + data = data + except: + data = '' startTime = math.floor(time.time()) # we should keep a hash DB of requests (with hmac) to prevent replays action = request.args.get('action') @@ -129,6 +141,15 @@ class API: resp = Response('pong') elif action == 'stats': resp = Response('me_irl') + elif action == 'site': + block = data + siteData = self._core.getData(data) + response = 'not found' + if siteData != '' and siteData != False: + self.mimeType = 'text/html' + response = siteData.split('-', 2)[-1] + resp = Response(response) + else: resp = Response('(O_o) Dude what? (invalid command)') endTime = math.floor(time.time()) @@ -149,7 +170,7 @@ class API: requestingPeer = request.args.get('myID') data = request.args.get('data') try: - data + data = data except: data = '' if action == 'firstConnect': @@ -175,7 +196,7 @@ class API: resp = Response('') # setData should be something the communicator initiates, not this api elif action == 'getData': - resp = self._core.getData(data) + resp = base64.b64encode(self._core.getData(data)) if resp == False: abort(404) resp = "" diff --git a/onionr/communicator.py b/onionr/communicator.py index da36179b..f316d14f 100755 --- a/onionr/communicator.py +++ b/onionr/communicator.py @@ -19,7 +19,7 @@ and code to operate as a daemon, getting commands from the command queue databas You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import sqlite3, requests, hmac, hashlib, time, sys, os, math, logger, urllib.parse, random +import sqlite3, requests, hmac, hashlib, time, sys, os, math, logger, urllib.parse, random, base64 import core, onionrutils, onionrcrypto, netcontroller, onionrproofs, btc, config, onionrplugins as plugins class OnionrCommunicate: @@ -239,6 +239,10 @@ class OnionrCommunicate: for i in peerList: hasher = hashlib.sha3_256() data = self.performGet('getData', i, hash) + try: + base64.b64decode(data) + except binascii.Error: + data = b'' if data == False or len(data) > 10000000: continue hasher.update(data.encode()) diff --git a/onionr/core.py b/onionr/core.py index 78bd6aff..4b6d8d88 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -258,7 +258,7 @@ class Core: Simply return the data associated to a hash ''' try: - dataFile = open(self.blockDataLocation + hash + '.dat') + dataFile = open(self.blockDataLocation + hash + '.dat', 'rb') data = dataFile.read() dataFile.close() except FileNotFoundError: @@ -281,8 +281,8 @@ class Core: pass # TODO: properly check if block is already saved elsewhere #raise Exception("Data is already set for " + dataHash) else: - blockFile = open(blockFileName, 'w') - blockFile.write(data.decode()) + blockFile = open(blockFileName, 'wb') + blockFile.write(data) blockFile.close() conn = sqlite3.connect(self.blockDB) diff --git a/onionr/onionr.py b/onionr/onionr.py index 395dcb75..e9bd8f15 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -175,6 +175,7 @@ class Onionr: 'add-addr': self.addAddress, 'addaddr': self.addAddress, 'addaddress': self.addAddress, + 'addfile': self.addFile, 'introduce': self.onionrCore.introduceNode, 'connect': self.addAddress @@ -196,6 +197,7 @@ class Onionr: 'add-msg': 'Broadcasts a message to the Onionr network', 'pm': 'Adds a private message to block', 'get-pms': 'Shows private messages sent to you', + 'addfile': 'Create an Onionr block from a file', 'introduce': 'Introduce your node to the public Onionr network (DAEMON MUST BE RUNNING)', } @@ -369,7 +371,7 @@ class Onionr: addedHash = self.onionrCore.setData(messageToAdd) self.onionrCore.addToBlockDB(addedHash, selfInsert=True) self.onionrCore.setBlockType(addedHash, 'txt') - + logger.info("inserted your message as block: " + addedHash) return def getPMs(self): @@ -556,5 +558,20 @@ class Onionr: retval = retVal.read() except FileNotFoundError: return retVal + + def addFile(self): + '''command to add a file to the onionr network''' + if len(sys.argv) >= 2: + newFile = sys.argv[2] + logger.info('Attempting to add file...') + try: + with open(newFile, 'r') as new: + new = new.read() + except FileNotFoundError: + logger.warn('That file does not exist. Improper path?') + else: + print(new) + self.onionrCore.insertBlock(new, header='bin') + Onionr() diff --git a/onionr/static-data/bootstrap-nodes.txt b/onionr/static-data/bootstrap-nodes.txt index 7afadcc1..72e08794 100644 --- a/onionr/static-data/bootstrap-nodes.txt +++ b/onionr/static-data/bootstrap-nodes.txt @@ -1 +1,2 @@ onionisrgccylxpr.onion +aaronk3mcmglj6qedwptg62yl3wxxjwba2ucpoobrn7iudcacdxtrfad.onion