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.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(b'-', 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,9 @@ class API:
resp = Response('')
# setData should be something the communicator initiates, not this api
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:
abort(404)
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
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
class OnionrCommunicate:
@ -241,17 +241,21 @@ class OnionrCommunicate:
data = self.performGet('getData', i, hash)
if data == False or len(data) > 10000000:
continue
hasher.update(data.encode())
try:
data = base64.b64decode(data)
except binascii.Error:
data = b''
hasher.update(data)
digest = hasher.hexdigest()
if type(digest) is bytes:
digest = digest.decode()
if digest == hash.strip():
self._core.setData(data)
if data.startswith('-txt-'):
self._core.setBlockType(hash, 'txt')
logger.info('Successfully obtained data for ' + hash, timestamp=True)
if len(data) < 120:
logger.debug('Block text:\n' + data)
if data.startswith(b'-txt-'):
self._core.setBlockType(hash, 'txt')
if len(data) < 120:
logger.debug('Block text:\n' + data.decode())
else:
logger.warn("Failed to validate " + hash + " " + " hash calculated was " + digest)
@ -263,13 +267,20 @@ class OnionrCommunicate:
'''
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)
'''
if not peer.endswith('.onion') and not peer.endswith('.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)
if not peer in self.peerData:

View File

@ -44,6 +44,9 @@ class Core:
self.addressDB = 'data/address.db'
self.hsAdder = ''
self.bootstrapFileLocation = 'static-data/bootstrap-nodes.txt'
self.bootstrapList = []
if not os.path.exists('data/'):
os.mkdir('data/')
if not os.path.exists('data/blocks/'):
@ -55,9 +58,19 @@ class Core:
with open('data/hs/hostname', 'r') as hs:
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)
# Initialize the crypto object
self._crypto = onionrcrypto.OnionrCrypto(self)
except Exception as error:
logger.error('Failed to initialize core Onionr library.', error=error)
logger.fatal('Cannot recover from error.')
@ -245,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:
@ -257,8 +270,10 @@ class Core:
'''
Set the data assciated with a hash
'''
data = data.encode()
data = data
hasher = hashlib.sha3_256()
if not type(data) is bytes:
data = data.encode()
hasher.update(data)
dataHash = hasher.hexdigest()
if type(dataHash) is bytes:
@ -268,8 +283,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)
@ -574,8 +589,10 @@ class Core:
announceAmount = 2
nodeList = self.listAdders()
if len(nodeList) == 0:
self.addAddress('onionragxuddecmg.onion')
nodeList.append('onionragxuddecmg.onion')
for i in self.bootstrapList:
if self._utils.validateID(i):
self.addAddress(i)
nodeList.append(i)
if announceAmount > len(nodeList):
announceAmount = len(nodeList)
for i in range(announceAmount):

View File

@ -34,7 +34,7 @@ except ImportError:
ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech'
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:
def __init__(self):
@ -179,6 +179,7 @@ class Onionr:
'add-addr': self.addAddress,
'addaddr': self.addAddress,
'addaddress': self.addAddress,
'addfile': self.addFile,
'introduce': self.onionrCore.introduceNode,
'connect': self.addAddress
@ -200,6 +201,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)',
}
@ -373,7 +375,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):
@ -557,8 +559,23 @@ class Onionr:
retVal = ''
try:
with open('./data/hs/hostname', 'r') as hostname:
retval = retVal.read()
retVal = hostname.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()

View File

@ -167,7 +167,7 @@ class OnionrCrypto:
return binascii.hexlify(nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE))
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()
public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder())
return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode())

View File

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