From 557ffa2f4a1324ae2bff4c2b9403229f51bf5e4b Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Fri, 1 Feb 2019 00:38:12 -0600 Subject: [PATCH] moved a couple files, work on mail interface, improvements to web + blockapi for block decryption --- README.md | 12 ++++--- onionr/api.py | 40 ++++++++++++++++++++--- onionr/core.py | 4 +-- onionr/{ => etc}/onionrvalues.py | 0 onionr/{ => etc}/pgpwords.py | 0 onionr/onionrblockapi.py | 7 +++- onionr/onionrutils.py | 3 +- onionr/static-data/bootstrap-nodes.txt | 2 +- onionr/static-data/www/mail/index.html | 6 ++-- onionr/static-data/www/mail/mail.js | 28 ++++++++++++++++ onionr/static-data/www/private/index.html | 1 + onionr/static-data/www/shared/misc.js | 16 ++++++++- 12 files changed, 101 insertions(+), 18 deletions(-) rename onionr/{ => etc}/onionrvalues.py (100%) rename onionr/{ => etc}/pgpwords.py (100%) diff --git a/README.md b/README.md index 98297240..c87b3544 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,14 @@

+

+ Anonymous P2P storage network +

+ (***pre-alpha quality & experimental, not well tested or easy to use yet***) [![Open Source Love](https://badges.frapsoft.com/os/v3/open-source.png?v=103)](https://github.com/ellerbrock/open-source-badges/) - -Anonymous P2P platform, using Tor & I2P. -
**The main repository for this software is at https://gitlab.com/beardog/Onionr/** @@ -19,9 +20,9 @@ Anonymous P2P platform, using Tor & I2P. Onionr is a decentralized, peer-to-peer data storage network, designed to be anonymous and resistant to (meta)data analysis and spam. -Onionr stores data in independent packages referred to as 'blocks' (not to be confused with a blockchain). The blocks are synced to all other nodes in the network. Blocks and user IDs cannot be easily proven to have been created by particular nodes (only inferred). +Onionr stores data in independent packages referred to as 'blocks' (not to be confused with a blockchain). The blocks are synced to all other nodes in the network. Blocks and user IDs cannot be easily proven to have been created by particular nodes (only inferred). Even if there is enough evidence to believe a particular node created a block, nodes still operate behind Tor or I2P and as such are not trivially known to be at a particular IP address. -Users are identified by ed25519 public keys, which can be used to sign blocks (optional) or send encrypted data. +Users are identified by ed25519 public keys, which can be used to sign blocks or send encrypted data. Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion. @@ -33,6 +34,7 @@ Onionr can be used for mail, as a social network, instant messenger, file sharin * [X] Optional non-encrypted blocks, useful for blog posts or public file sharing * [X] Easy API system for integration to websites * [X] Metadata analysis resistance +* [X] Transport agnosticism **Onionr API and functionality is subject to non-backwards compatible change during pre-alpha development** diff --git a/onionr/api.py b/onionr/api.py index 029da837..dbd79321 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -139,8 +139,8 @@ class PublicAPI: if clientAPI._utils.validateHash(data): if data not in self.hideBlocks: if data in clientAPI._core.getBlockList(): - block = Block(hash=data.encode(), core=clientAPI._core) - resp = base64.b64encode(block.getRaw().encode()).decode() + block = self.clientAPI.getBlockData(data).encode() + resp = base64.b64encode(block).decode() if len(resp) == 0: abort(404) resp = "" @@ -310,7 +310,7 @@ class API: @app.route('/mail/', endpoint='mail') def loadMail(path): - return send_from_directory('static-data/www/mail/', '') + return send_from_directory('static-data/www/mail/', path) @app.route('/mail/', endpoint='mailindex') def loadMailIndex(): return send_from_directory('static-data/www/mail/', 'index.html') @@ -358,7 +358,7 @@ class API: return Response(','.join(blocks)) @app.route('/gethtmlsafeblockdata/') - def getData(name): + def getSafeData(name): resp = '' if self._core._utils.validateHash(name): try: @@ -368,6 +368,21 @@ class API: else: abort(404) return Response(resp) + + @app.route('/getblockdata/') + def getData(name): + resp = "" + if self._core._utils.validateHash(name): + if name in self._core.getBlockList(): + try: + resp = self.getBlockData(name, decrypt=True) + except ValueError: + pass + else: + abort(404) + else: + abort(404) + return Response(resp) @app.route('/site/', endpoint='site') def site(name): @@ -452,4 +467,19 @@ class API: return self._utils.getEpoch - startTime except AttributeError: # Don't error on race condition with startup - pass \ No newline at end of file + pass + + def getBlockData(self, bHash, decrypt=False): + bl = Block(bHash, core=self._core) + if decrypt: + bl.decrypt() + if bl.isEncrypted and not bl.decrypted: + raise ValueError + + 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 + return json.dumps(retData) \ No newline at end of file diff --git a/onionr/core.py b/onionr/core.py index b14eee1f..8634ab1f 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -20,9 +20,10 @@ import sqlite3, os, sys, time, math, base64, tarfile, nacl, logger, json, netcontroller, math, config, uuid from onionrblockapi import Block -import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions, onionrvalues +import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions import onionrblacklist, onionrusers import dbcreator, onionrstorage, serializeddata +from etc import onionrvalues if sys.version_info < (3, 6): try: @@ -868,5 +869,4 @@ class Core: else: logger.error('Onionr daemon is not running.') return False - return diff --git a/onionr/onionrvalues.py b/onionr/etc/onionrvalues.py similarity index 100% rename from onionr/onionrvalues.py rename to onionr/etc/onionrvalues.py diff --git a/onionr/pgpwords.py b/onionr/etc/pgpwords.py similarity index 100% rename from onionr/pgpwords.py rename to onionr/etc/pgpwords.py diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index c8f12a54..09dd77ea 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -25,7 +25,7 @@ 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, core = None, type = None, content = None, expire=None): + def __init__(self, hash = None, core = None, type = None, content = None, expire=None, decrypt=False): # take from arguments # sometimes people input a bytes object instead of str in `hash` if (not hash is None) and isinstance(hash, bytes): @@ -51,6 +51,7 @@ class Block: self.decrypted = False self.signer = None self.validSig = False + self.autoDecrypt = decrypt # handle arguments if self.getCore() is None: @@ -80,6 +81,7 @@ class Block: self.bmetadata = json.loads(bmeta) self.signature = core._crypto.pubKeyDecrypt(self.signature, anonymous=anonymous, encodedData=encodedData) self.signer = core._crypto.pubKeyDecrypt(self.signer, anonymous=anonymous, encodedData=encodedData) + self.bheader['signer'] = self.signer.decode() self.signedData = json.dumps(self.bmetadata) + self.bcontent.decode() try: assert self.bmetadata['forwardEnc'] is True @@ -190,6 +192,9 @@ class Block: if len(self.getRaw()) <= config.get('allocations.blockCache', 500000): self.cache() + + if self.autoDecrypt: + self.decrypt() return True except Exception as e: diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 3260a42b..b34eb948 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -24,7 +24,8 @@ from onionrblockapi import Block import onionrexceptions from onionr import API_VERSION import onionrevents -import pgpwords, onionrusers, storagecounter +import onionrusers, storagecounter +from etc import pgpwords if sys.version_info < (3, 6): try: import sha3 diff --git a/onionr/static-data/bootstrap-nodes.txt b/onionr/static-data/bootstrap-nodes.txt index ad126465..93dec7ce 100644 --- a/onionr/static-data/bootstrap-nodes.txt +++ b/onionr/static-data/bootstrap-nodes.txt @@ -1 +1 @@ -svlegnabtuh3dq6ncmzqmpnxzik5mita5x22up4tai2ekngzcgqbnbqd.onion \ No newline at end of file +dd3llxdp5q6ak3zmmicoy3jnodmroouv2xr7whkygiwp3rl7nf23gdad.onion \ No newline at end of file diff --git a/onionr/static-data/www/mail/index.html b/onionr/static-data/www/mail/index.html index 73481922..a08dbf55 100644 --- a/onionr/static-data/www/mail/index.html +++ b/onionr/static-data/www/mail/index.html @@ -12,10 +12,12 @@
- Onionr Web Mail + Onionr Mail
- + +
+ \ No newline at end of file diff --git a/onionr/static-data/www/mail/mail.js b/onionr/static-data/www/mail/mail.js index e69de29b..bafbda6d 100644 --- a/onionr/static-data/www/mail/mail.js +++ b/onionr/static-data/www/mail/mail.js @@ -0,0 +1,28 @@ +pms = '' +threadPart = document.getElementById('threads') +function getInbox(){ + for(var i = 0; i < pms.length; i++) { + fetch('/getblockdata/' + pms[i], { + headers: { + "token": webpass + }}) + .then((resp) => resp.json()) // Transform the data into json + .then(function(resp) { + var entry = document.createElement('div') + entry.innerHTML = resp['meta']['time'] + ' - ' + resp['meta']['signer'] + threadPart.appendChild(entry) + }) + } + +} + +fetch('/getblocksbytype/pm', { + headers: { + "token": webpass + }}) +.then((resp) => resp.text()) // Transform the data into json +.then(function(data) { + pms = data.split(',') + getInbox() + }) + diff --git a/onionr/static-data/www/private/index.html b/onionr/static-data/www/private/index.html index 8907195b..3e239eb0 100644 --- a/onionr/static-data/www/private/index.html +++ b/onionr/static-data/www/private/index.html @@ -18,6 +18,7 @@ Onionr Web Control Panel
+

Mail

Stats

Uptime:

Stored Blocks:

diff --git a/onionr/static-data/www/shared/misc.js b/onionr/static-data/www/shared/misc.js index cd3dbba1..c9b3790e 100644 --- a/onionr/static-data/www/shared/misc.js +++ b/onionr/static-data/www/shared/misc.js @@ -5,7 +5,7 @@ if (typeof webpass == "undefined"){ } else{ localStorage['webpass'] = webpass - document.location.hash = '' + //document.location.hash = '' } if (typeof webpass == "undefined" || webpass == ""){ alert('Web password was not found in memory or URL') @@ -28,3 +28,17 @@ function overlay(overlayID) { el = document.getElementById(overlayID) el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible" } + +var passLinks = document.getElementsByClassName("idLink") + for(var i = 0; i < passLinks.length; i++) { + passLinks[i].href += '#' + webpass + } + +var refreshLinks = document.getElementsByClassName("refresh") + +for(var i = 0; i < refreshLinks.length; i++) { + //Can't use .reload because of webpass + refreshLinks[i].onclick = function(){ + location.reload() + } +}