work on adding peers, improving docs, and minor bug fixes

This commit is contained in:
Kevin Froman 2018-01-13 18:07:13 -06:00
parent 1006be971b
commit 097c57b97a
No known key found for this signature in database
GPG Key ID: 0D414D0FE405B63B
6 changed files with 116 additions and 18 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
__pycache__/ __pycache__/
data/config.ini data/config.ini
data/*.db data/*.db
data-old/*
dev-enabled dev-enabled

View File

@ -1,6 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
''' '''
Onionr - P2P Microblogging Platform & Social network. Run with 'help' for usage. Onionr - P2P Microblogging Platform & Social network.
This file contains both the OnionrCommunicate class for communcating with peers
and code to operate as a daemon, getting commands from the command queue database (see core.Core.daemonQueue)
'''
'''
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -14,24 +19,30 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import sqlite3, requests, hmac, hashlib, time import sqlite3, requests, hmac, hashlib, time, sys
import core import core
class OnionrCommunicate: class OnionrCommunicate:
def __init__(self): def __init__(self):
''' OnionrCommunicate
This class handles communication with nodes in the Onionr network.
'''
self._core = core.Core() self._core = core.Core()
while True:
print('Onionr daemon running')
time.sleep(2)
return return
def getRemotePeerKey(self, peerID): def getRemotePeerKey(self, peerID):
'''This function contacts a peer and gets their main PGP key. '''This function contacts a peer and gets their main PGP key.
This is safe because Tor or I2P is used, but it does not insure that the person is who they say they are
This is safe because Tor or I2P is used, but it does not ensure that the person is who they say they are
''' '''
url = 'http://' + peerID + '/public/?action=getPGP' url = 'http://' + peerID + '/public/?action=getPGP'
r = requests.get(url, headers=headers) r = requests.get(url, headers=headers)
response = r.text response = r.text
return response return response
shouldRun = False
try:
if sys.argv[1] == 'run':
OnionrCommunicate() shouldRun = True
except IndexError:
pass
if shouldRun:
OnionrCommunicate()

View File

@ -37,8 +37,8 @@ class Core:
# This function simply adds a peer to the DB # This function simply adds a peer to the DB
conn = sqlite3.connect(self.peerDB) conn = sqlite3.connect(self.peerDB)
c = conn.cursor() c = conn.cursor()
t = (peerID, name) t = (peerID, name, 'unknown')
c.execute('Insert into users (id, name) values(?, ?);', t) c.execute('Insert into users (id, name, dateSeen) values(?, ?, ?);', t)
conn.commit() conn.commit()
conn.close() conn.close()
return True return True

72
docs/onionr-draft.md Normal file
View File

@ -0,0 +1,72 @@
# Onionr Protocol Spec
A social network/microblogging platform for Tor & I2P
Draft Dec 25 2017
notes:
Use Blowfish in addition with AES?
# Overview
Onionr is an encrypted microblogging & mailing system designed in the spirit of Twitter.
There are no central servers and all traffic is peer to peer by default (routed via Tor or I2P).
User IDs are simply Tor onion service/I2P host id + PGP fingerprint.
Clients consolidate feeds from peers into 1 “timeline” using RSS format.
Private messages are only accessible by the intended peer based on the PGP id.
Onionr is not intended to be a replacement for Ricochet or OnionShare.
All traffic is over onion/I2P because if only some was, then that would make that traffic inherently suspicious.
## Goals:
• Selective sharing of information with friends & public
• Secure & semi-anonymous direct messaging
• Forward secrecy
• Defense in depth
• Data should be secure for years to come, quantum safe (though not necessarily every “layer”)
• Decentralization
* Avoid browser-based exploits that plague similar software
* Avoid timing attacks & unexpected metadata leaks
## Assumptions:
• Tor & I2Ps transport protocols & AES-256 are not broken, sha3-512 2nd preimage attacks will remain infeasible indefinitely
• All traffic is logged indefinitely by powerful adversaries
## Protocol
Clients MUST use HTTP(s) to communicate with one another to maintain compatibility cross platform. HTTPS is recommended, but HTTP is acceptable because Tor & I2P provide transport layer security.
## Connections
When a node first comes online, it attempts to bootstrap using a default list provided by a client.
When two peers connect, they exchange PGP public keys and then generate a shared AES-SHA3-512 HMAC token. These keys are stored in a peer database until expiry.
HMAC tokens are regenerated either every X many communications with a peer or every X minutes. Every 10 communications or every 24 hours is a recommended default.
All valid requests with HMAC should be recorded until used HMAC's expiry to prevent replay attacks.
Peer Types
* Friends:
* Encrypted friends only posts to one another
* Usually less strict rate & storage limits
* OPTIONALLY sign one anothers keys. Users may not want to do this in order to avoid exposing their entire friends list.
• Strangers:
* Used for storage of encrypted or public information
* Can only read public posts
* Usually stricter rate & storage limits
## Data Storage/Delivery
Posts (public or friends only) are stored across the network.
Private messages SHOULD be delivered directly if both peers are online, otherwise stored in the network.
Data SHOULD be stored in an entirely encrypted state when a client is offline, including metadata. Data SHOULD be stored in a minimal size with garbage data to ensure some level of plausible deniablity.
Data SHOULD be stored as long as the nodes user prefers and only erased once disk quota is reached due to new data.
Posts
Posts can contain text and images. All posts MUST be time stamped.
Images SHOULD not be displayed by non-friends by default, to prevent unwanted viewing of offensive material & to reduce attack surface.
All received posts must be verified to be stored and/or displayed to the user.
Posts have two settings:
• Friends only:
◦ Posts MUST be encrypted to all trusted peers via AES256-HMAC-SHA256 and PGP signed (signed before encryption) and time stamped to prevent replaying. A temporary RSA key for use in every post (or message) is exchanged every X many configured post (or message), for use in addition with PGP and the HMAC.
• Public:
◦ Posts MUST be PGP signed, and MUST NOT use any encryption.
## Private Messages
Private messages are messages that can have attached images. They MUST be encrypted via AES256-HMAC-SHA256 and PGP signed (signed before encryption) and time stamped to prevent replaying. A temporary RSA key for use in every message is exchanged every X many configured messages (or posts), for use in addition with PGP and the HMAC.
When both peers are online messages SHOULD be dispatched directly between peers.
All messages must be verified prior to being displayed.
CLients SHOULD allow configurable message padding.
## Spam mitigation
To send or receive data, a node can optionally request that the other node generate a hash that when in hexadecimal representation contains a random string at a random location in the string. Clients will configure what difficulty to request, and what difficulty is acceptable for themselves to perform. Difficulty should correlate with recent network & disk usage and data size. Friends can be configured to have less strict (to non existent) limits, separately from strangers. (proof of work).
Rate limits can be strict, as Onionr is not intended to be an instant messaging application.

View File

@ -1,6 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
''' '''
Onionr - P2P Microblogging Platform & Social network. Run with 'help' for usage. Onionr - P2P Microblogging Platform & Social network.
Onionr is the name for both the protocol and the original/reference software.
Run with 'help' for usage.
'''
'''
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -21,6 +27,10 @@ from colors import Colors
class Onionr: class Onionr:
def __init__(self): def __init__(self):
'''Main Onionr class. This is for the CLI program, and does not handle much of the logic.
In general, external programs and plugins should not use this class.
'''
if os.path.exists('dev-enabled'): if os.path.exists('dev-enabled'):
print('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)') print('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)')
self._developmentMode = True self._developmentMode = True
@ -35,8 +45,11 @@ class Onionr:
# Get configuration and Handle commands # Get configuration and Handle commands
self.debug = False # Whole application debugging self.debug = False # Whole application debugging
try:
os.chdir(sys.path[0]) os.chdir(sys.path[0])
except FileNotFoundError:
pass
if os.path.exists('data-encrypted.dat'): if os.path.exists('data-encrypted.dat'):
while True: while True:
print('Enter password to decrypt:') print('Enter password to decrypt:')
@ -94,7 +107,7 @@ class Onionr:
return return
def daemon(self): def daemon(self):
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true": if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
subprocess.Popen(["./communicator.py"]) subprocess.Popen(["./communicator.py", "run"])
print('Started communicator') print('Started communicator')
api.API(self.config, self.debug) api.API(self.config, self.debug)
return return

View File

@ -49,9 +49,10 @@ class OnionrTests(unittest.TestCase):
print('Running peer db insertion test') print('Running peer db insertion test')
import core import core
myCore = core.Core() myCore = core.Core()
if not os.path.exists('data/peers.db'):
myCore.createPeerDB() myCore.createPeerDB()
if myCore.addPeer('test'): if myCore.addPeer('test'):
self.asserTrue(True) self.assertTrue(True)
else: else:
self.assertTrue(False) self.assertTrue(False)
def testData_b_Encrypt(self): def testData_b_Encrypt(self):