Merge branch 'crypto' of https://github.com/beardog108/Onionr into crypto

master
Arinerron 2018-04-22 20:42:50 -07:00
commit 36d9ebd4f1
6 changed files with 94 additions and 23 deletions

View File

@ -68,6 +68,8 @@ class API:
self.clientToken = config.get('client')['client_hmac'] self.clientToken = config.get('client')['client_hmac']
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
self.mimeType = 'text/plain'
with open('data/time-bypass.txt', 'w') as bypass: with open('data/time-bypass.txt', 'w') as bypass:
bypass.write(self.timeBypassToken) bypass.write(self.timeBypassToken)
@ -96,12 +98,17 @@ class API:
def afterReq(resp): def afterReq(resp):
if not self.requestFailed: if not self.requestFailed:
resp.headers['Access-Control-Allow-Origin'] = '*' resp.headers['Access-Control-Allow-Origin'] = '*'
else: #else:
resp.headers['server'] = 'Onionr' # resp.headers['server'] = 'Onionr'
resp.headers['Content-Type'] = 'text/plain' resp.headers['Content-Type'] = self.mimeType
resp.headers["Content-Security-Policy"] = "default-src 'none'" 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-Frame-Options'] = 'deny'
resp.headers['X-Content-Type-Options'] = "nosniff" 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 return resp
@ -111,6 +118,11 @@ class API:
timingToken = '' timingToken = ''
else: else:
timingToken = request.args.get('timingToken') timingToken = request.args.get('timingToken')
data = request.args.get('data')
try:
data = data
except:
data = ''
startTime = math.floor(time.time()) startTime = math.floor(time.time())
# we should keep a hash DB of requests (with hmac) to prevent replays # we should keep a hash DB of requests (with hmac) to prevent replays
action = request.args.get('action') action = request.args.get('action')
@ -129,6 +141,15 @@ class API:
resp = Response('pong') resp = Response('pong')
elif action == 'stats': elif action == 'stats':
resp = Response('me_irl') 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(b'-', 2)[-1]
resp = Response(response)
else: else:
resp = Response('(O_o) Dude what? (invalid command)') resp = Response('(O_o) Dude what? (invalid command)')
endTime = math.floor(time.time()) endTime = math.floor(time.time())
@ -149,7 +170,7 @@ class API:
requestingPeer = request.args.get('myID') requestingPeer = request.args.get('myID')
data = request.args.get('data') data = request.args.get('data')
try: try:
data data = data
except: except:
data = '' data = ''
if action == 'firstConnect': if action == 'firstConnect':
@ -175,7 +196,9 @@ class API:
resp = Response('') resp = Response('')
# setData should be something the communicator initiates, not this api # setData should be something the communicator initiates, not this api
elif action == 'getData': elif action == 'getData':
resp = self._core.getData(data) if self._utils.validateHash(data):
if not os.path.exists('data/blocks/' + data + '.db'):
resp = base64.b64encode(self._core.getData(data))
if resp == False: if resp == False:
abort(404) abort(404)
resp = "" resp = ""

View File

@ -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 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, sys, os, math, logger, urllib.parse, random import sqlite3, requests, hmac, hashlib, time, sys, os, math, logger, urllib.parse, random, base64, binascii
import core, onionrutils, onionrcrypto, netcontroller, onionrproofs, btc, config, onionrplugins as plugins import core, onionrutils, onionrcrypto, netcontroller, onionrproofs, btc, config, onionrplugins as plugins
class OnionrCommunicate: class OnionrCommunicate:
@ -241,17 +241,21 @@ class OnionrCommunicate:
data = self.performGet('getData', i, hash) data = self.performGet('getData', i, hash)
if data == False or len(data) > 10000000: if data == False or len(data) > 10000000:
continue continue
hasher.update(data.encode()) try:
data = base64.b64decode(data)
except binascii.Error:
data = b''
hasher.update(data)
digest = hasher.hexdigest() digest = hasher.hexdigest()
if type(digest) is bytes: if type(digest) is bytes:
digest = digest.decode() digest = digest.decode()
if digest == hash.strip(): if digest == hash.strip():
self._core.setData(data) self._core.setData(data)
if data.startswith('-txt-'):
self._core.setBlockType(hash, 'txt')
logger.info('Successfully obtained data for ' + hash, timestamp=True) logger.info('Successfully obtained data for ' + hash, timestamp=True)
if len(data) < 120: if data.startswith(b'-txt-'):
logger.debug('Block text:\n' + data) self._core.setBlockType(hash, 'txt')
if len(data) < 120:
logger.debug('Block text:\n' + data.decode())
else: else:
logger.warn("Failed to validate " + hash + " " + " hash calculated was " + digest) logger.warn("Failed to validate " + hash + " " + " hash calculated was " + digest)
@ -263,13 +267,20 @@ class OnionrCommunicate:
''' '''
return urllib.parse.quote_plus(data) return urllib.parse.quote_plus(data)
def performGet(self, action, peer, data=None, skipHighFailureAddress=False, peerType='tor'): def performGet(self, action, peer, data=None, skipHighFailureAddress=False, peerType='tor', selfCheck=True):
''' '''
Performs a request to a peer through Tor or i2p (currently only Tor) Performs a request to a peer through Tor or i2p (currently only Tor)
''' '''
if not peer.endswith('.onion') and not peer.endswith('.onion/'): if not peer.endswith('.onion') and not peer.endswith('.onion/'):
raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion') raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion')
if len(self._core.hsAdder.strip()) == 0:
raise Exception("Could not perform self address check in performGet due to not knowing our address")
if selfCheck:
if peer.replace('/', '') == self._core.hsAdder:
logger.warn('Tried to performget to own hidden service, but selfCheck was not set to false')
return
# Store peer in peerData dictionary (non permanent) # Store peer in peerData dictionary (non permanent)
if not peer in self.peerData: if not peer in self.peerData:

View File

@ -44,6 +44,9 @@ class Core:
self.addressDB = 'data/address.db' self.addressDB = 'data/address.db'
self.hsAdder = '' self.hsAdder = ''
self.bootstrapFileLocation = 'static-data/bootstrap-nodes.txt'
self.bootstrapList = []
if not os.path.exists('data/'): if not os.path.exists('data/'):
os.mkdir('data/') os.mkdir('data/')
if not os.path.exists('data/blocks/'): if not os.path.exists('data/blocks/'):
@ -55,9 +58,19 @@ class Core:
with open('data/hs/hostname', 'r') as hs: with open('data/hs/hostname', 'r') as hs:
self.hsAdder = hs.read() self.hsAdder = hs.read()
# Load bootstrap address list
if os.path.exists(self.bootstrapFileLocation):
with open(self.bootstrapFileLocation, 'r') as bootstrap:
bootstrap = bootstrap.read()
for i in bootstrap.split('\n'):
self.bootstrapList.append(i)
else:
logger.warn('Warning: address bootstrap file not found ' + self.bootstrapFileLocation)
self._utils = onionrutils.OnionrUtils(self) self._utils = onionrutils.OnionrUtils(self)
# Initialize the crypto object # Initialize the crypto object
self._crypto = onionrcrypto.OnionrCrypto(self) self._crypto = onionrcrypto.OnionrCrypto(self)
except Exception as error: except Exception as error:
logger.error('Failed to initialize core Onionr library.', error=error) logger.error('Failed to initialize core Onionr library.', error=error)
logger.fatal('Cannot recover from error.') logger.fatal('Cannot recover from error.')
@ -245,7 +258,7 @@ class Core:
Simply return the data associated to a hash Simply return the data associated to a hash
''' '''
try: try:
dataFile = open(self.blockDataLocation + hash + '.dat') dataFile = open(self.blockDataLocation + hash + '.dat', 'rb')
data = dataFile.read() data = dataFile.read()
dataFile.close() dataFile.close()
except FileNotFoundError: except FileNotFoundError:
@ -257,8 +270,10 @@ class Core:
''' '''
Set the data assciated with a hash Set the data assciated with a hash
''' '''
data = data.encode() data = data
hasher = hashlib.sha3_256() hasher = hashlib.sha3_256()
if not type(data) is bytes:
data = data.encode()
hasher.update(data) hasher.update(data)
dataHash = hasher.hexdigest() dataHash = hasher.hexdigest()
if type(dataHash) is bytes: if type(dataHash) is bytes:
@ -268,8 +283,8 @@ class Core:
pass # TODO: properly check if block is already saved elsewhere pass # TODO: properly check if block is already saved elsewhere
#raise Exception("Data is already set for " + dataHash) #raise Exception("Data is already set for " + dataHash)
else: else:
blockFile = open(blockFileName, 'w') blockFile = open(blockFileName, 'wb')
blockFile.write(data.decode()) blockFile.write(data)
blockFile.close() blockFile.close()
conn = sqlite3.connect(self.blockDB) conn = sqlite3.connect(self.blockDB)
@ -574,8 +589,10 @@ class Core:
announceAmount = 2 announceAmount = 2
nodeList = self.listAdders() nodeList = self.listAdders()
if len(nodeList) == 0: if len(nodeList) == 0:
self.addAddress('onionragxuddecmg.onion') for i in self.bootstrapList:
nodeList.append('onionragxuddecmg.onion') if self._utils.validateID(i):
self.addAddress(i)
nodeList.append(i)
if announceAmount > len(nodeList): if announceAmount > len(nodeList):
announceAmount = len(nodeList) announceAmount = len(nodeList)
for i in range(announceAmount): for i in range(announceAmount):

View File

@ -34,7 +34,7 @@ except ImportError:
ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech' ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech'
ONIONR_VERSION = '0.0.0' # for debugging and stuff ONIONR_VERSION = '0.0.0' # for debugging and stuff
API_VERSION = '1' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes knows how to communicate without learning too much information about you. API_VERSION = '2' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes knows how to communicate without learning too much information about you.
class Onionr: class Onionr:
def __init__(self): def __init__(self):
@ -179,6 +179,7 @@ class Onionr:
'add-addr': self.addAddress, 'add-addr': self.addAddress,
'addaddr': self.addAddress, 'addaddr': self.addAddress,
'addaddress': self.addAddress, 'addaddress': self.addAddress,
'addfile': self.addFile,
'introduce': self.onionrCore.introduceNode, 'introduce': self.onionrCore.introduceNode,
'connect': self.addAddress 'connect': self.addAddress
@ -200,6 +201,7 @@ class Onionr:
'add-msg': 'Broadcasts a message to the Onionr network', 'add-msg': 'Broadcasts a message to the Onionr network',
'pm': 'Adds a private message to block', 'pm': 'Adds a private message to block',
'get-pms': 'Shows private messages sent to you', '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)', 'introduce': 'Introduce your node to the public Onionr network (DAEMON MUST BE RUNNING)',
} }
@ -373,7 +375,7 @@ class Onionr:
addedHash = self.onionrCore.setData(messageToAdd) addedHash = self.onionrCore.setData(messageToAdd)
self.onionrCore.addToBlockDB(addedHash, selfInsert=True) self.onionrCore.addToBlockDB(addedHash, selfInsert=True)
self.onionrCore.setBlockType(addedHash, 'txt') self.onionrCore.setBlockType(addedHash, 'txt')
logger.info("inserted your message as block: " + addedHash)
return return
def getPMs(self): def getPMs(self):
@ -557,8 +559,23 @@ class Onionr:
retVal = '' retVal = ''
try: try:
with open('./data/hs/hostname', 'r') as hostname: with open('./data/hs/hostname', 'r') as hostname:
retval = retVal.read() retVal = hostname.read()
except FileNotFoundError: except FileNotFoundError:
return retVal 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() Onionr()

View File

@ -167,7 +167,7 @@ class OnionrCrypto:
return binascii.hexlify(nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)) return binascii.hexlify(nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE))
def generatePubKey(self): def generatePubKey(self):
'''Generate a Ed25519 public key pair, return tuple of base64encoded pubkey, privkey''' '''Generate a Ed25519 public key pair, return tuple of base32encoded pubkey, privkey'''
private_key = nacl.signing.SigningKey.generate() private_key = nacl.signing.SigningKey.generate()
public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder()) public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder())
return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode()) return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode())

View File

@ -0,0 +1,3 @@
onionisrgccylxpr.onion
aaronk3mcmglj6qedwptg62yl3wxxjwba2ucpoobrn7iudcacdxtrfad.onion
onionragxuddecmg.onion