Merge remote-tracking branch 'origin/tempblocks' into onionrui
This commit is contained in:
commit
d5355fdc9e
35 changed files with 1273 additions and 414 deletions
|
@ -46,14 +46,15 @@ class OnionrCLIUI:
|
|||
showMenu = True
|
||||
isOnline = "No"
|
||||
firstRun = True
|
||||
choice = ''
|
||||
|
||||
if self.myCore._utils.localCommand('ping') == 'pong':
|
||||
firstRun = False
|
||||
|
||||
while showMenu:
|
||||
if firstRun:
|
||||
print("please wait while Onionr starts...")
|
||||
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||
logger.info("please wait while Onionr starts...")
|
||||
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
|
||||
time.sleep(30)
|
||||
firstRun = False
|
||||
|
||||
|
@ -91,7 +92,6 @@ Daemon Running: ''' + isOnline + '''
|
|||
elif choice in ("5", "daemon"):
|
||||
if isOnline == "Yes":
|
||||
print("Onionr daemon will shutdown...")
|
||||
#self.myCore._utils.localCommand("shutdown")
|
||||
self.myCore.daemonQueueAdd('shutdown')
|
||||
try:
|
||||
daemon.kill()
|
||||
|
|
5
onionr/static-data/default-plugins/encrypt/info.json
Normal file
5
onionr/static-data/default-plugins/encrypt/info.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name" : "encrypt",
|
||||
"version" : "1.0",
|
||||
"author" : "onionr"
|
||||
}
|
117
onionr/static-data/default-plugins/encrypt/main.py
Normal file
117
onionr/static-data/default-plugins/encrypt/main.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
'''
|
||||
Onionr - P2P Microblogging Platform & Social network
|
||||
|
||||
This default plugin allows users to encrypt/decrypt messages without using blocks
|
||||
'''
|
||||
'''
|
||||
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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
# Imports some useful libraries
|
||||
import logger, config, threading, time, readline, datetime, sys, json
|
||||
from onionrblockapi import Block
|
||||
import onionrexceptions, onionrusers
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
|
||||
class PlainEncryption:
|
||||
def __init__(self, api):
|
||||
self.api = api
|
||||
return
|
||||
def encrypt(self):
|
||||
# peer, data
|
||||
plaintext = ""
|
||||
encrypted = ""
|
||||
# detect if signing is enabled
|
||||
sign = True
|
||||
try:
|
||||
if sys.argv[3].lower() == 'false':
|
||||
sign = False
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if not self.api.get_core()._utils.validatePubKey(sys.argv[2]):
|
||||
raise onionrexceptions.InvalidPubkey
|
||||
except (ValueError, IndexError) as e:
|
||||
logger.error("Peer public key not specified")
|
||||
except onionrexceptions.InvalidPubkey:
|
||||
logger.error("Invalid public key")
|
||||
else:
|
||||
pubkey = sys.argv[2]
|
||||
# Encrypt if public key is valid
|
||||
logger.info("Please enter your message (ctrl-d or -q to stop):")
|
||||
try:
|
||||
for line in sys.stdin:
|
||||
if line == '-q\n':
|
||||
break
|
||||
plaintext += line
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
# Build Message to encrypt
|
||||
data = {}
|
||||
myPub = self.api.get_core()._crypto.pubKey
|
||||
if sign:
|
||||
data['sig'] = self.api.get_core()._crypto.edSign(plaintext, key=self.api.get_core()._crypto.privKey, encodeResult=True)
|
||||
data['sig'] = self.api.get_core()._utils.bytesToStr(data['sig'])
|
||||
data['signer'] = myPub
|
||||
data['data'] = plaintext
|
||||
data = json.dumps(data)
|
||||
plaintext = data
|
||||
encrypted = self.api.get_core()._crypto.pubKeyEncrypt(plaintext, pubkey, anonymous=True, encodedData=True)
|
||||
encrypted = self.api.get_core()._utils.bytesToStr(encrypted)
|
||||
print('ONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,))
|
||||
def decrypt(self):
|
||||
plaintext = ""
|
||||
data = ""
|
||||
logger.info("Please enter your message (ctrl-d or -q to stop):")
|
||||
try:
|
||||
for line in sys.stdin:
|
||||
if line == '-q\n':
|
||||
break
|
||||
data += line
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
if len(data) <= 1:
|
||||
return
|
||||
encrypted = data.replace('ONIONR ENCRYPTED DATA ', '').replace('END ENCRYPTED DATA', '')
|
||||
myPub = self.api.get_core()._crypto.pubKey
|
||||
decrypted = self.api.get_core()._crypto.pubKeyDecrypt(encrypted, privkey=self.api.get_core()._crypto.privKey, anonymous=True, encodedData=True)
|
||||
if decrypted == False:
|
||||
print("Decryption failed")
|
||||
else:
|
||||
data = json.loads(decrypted)
|
||||
print(data['data'])
|
||||
try:
|
||||
logger.info("Signing public key: %s" % (data['signer'],))
|
||||
assert self.api.get_core()._crypto.edVerify(data['data'], data['signer'], data['sig']) != False
|
||||
except (AssertionError, KeyError) as e:
|
||||
logger.warn("WARNING: THIS MESSAGE HAS A MISSING OR INVALID SIGNATURE")
|
||||
else:
|
||||
logger.info("Message has good signature.")
|
||||
return
|
||||
|
||||
|
||||
def on_init(api, data = None):
|
||||
'''
|
||||
This event is called after Onionr is initialized, but before the command
|
||||
inputted is executed. Could be called when daemon is starting or when
|
||||
just the client is running.
|
||||
'''
|
||||
|
||||
pluginapi = api
|
||||
encrypt = PlainEncryption(pluginapi)
|
||||
api.commands.register(['encrypt'], encrypt.encrypt)
|
||||
api.commands.register(['decrypt'], encrypt.decrypt)
|
||||
return
|
|
@ -45,9 +45,9 @@ class OnionrFlow:
|
|||
self.flowRunning = False
|
||||
if message == "q":
|
||||
self.flowRunning = False
|
||||
|
||||
expireTime = self.myCore._utils.getEpoch() + 43200
|
||||
if len(message) > 0:
|
||||
Block(content = message, type = 'txt', core = self.myCore).save()
|
||||
Block(content = message, type = 'txt', expire=expireTime, core = self.myCore).save()
|
||||
|
||||
logger.info("Flow is exiting, goodbye")
|
||||
return
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name" : "metadataprocessor",
|
||||
"version" : "1.0",
|
||||
"author" : "onionr"
|
||||
}
|
103
onionr/static-data/default-plugins/metadataprocessor/main.py
Normal file
103
onionr/static-data/default-plugins/metadataprocessor/main.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
'''
|
||||
Onionr - P2P Anonymous Storage Network
|
||||
|
||||
This processes metadata for Onionr blocks
|
||||
'''
|
||||
'''
|
||||
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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
# useful libraries
|
||||
import logger, config
|
||||
import os, sys, json, time, random, shutil, base64, getpass, datetime, re
|
||||
from onionrblockapi import Block
|
||||
import onionrusers, onionrexceptions
|
||||
|
||||
plugin_name = 'metadataprocessor'
|
||||
|
||||
# event listeners
|
||||
|
||||
def _processUserInfo(api, newBlock):
|
||||
'''
|
||||
Set the username for a particular user, from a signed block by them
|
||||
'''
|
||||
myBlock = newBlock
|
||||
peerName = myBlock.getMetadata('name')
|
||||
try:
|
||||
if len(peerName) > 20:
|
||||
raise onionrexceptions.InvalidMetdata('Peer name specified is too large')
|
||||
except TypeError:
|
||||
pass
|
||||
except onionrexceptions.InvalidMetadata:
|
||||
pass
|
||||
else:
|
||||
api.get_core().setPeerInfo(signer, 'name', peerName)
|
||||
logger.info('%s is now using the name %s.' % (signer, api.get_utils().escapeAnsi(peerName)))
|
||||
|
||||
def _processForwardKey(api, myBlock):
|
||||
'''
|
||||
Get the forward secrecy key specified by the user for us to use
|
||||
'''
|
||||
peer = onionrusers.OnionrUser(api.get_core(), myBlock.signer)
|
||||
key = myBlock.getMetadata('newFSKey')
|
||||
|
||||
# We don't need to validate here probably, but it helps
|
||||
if api.get_utils().validatePubKey(key):
|
||||
peer.addForwardKey(key)
|
||||
else:
|
||||
raise onionrexceptions.InvalidPubkey("%s is nota valid pubkey key" % (key,))
|
||||
|
||||
def on_processblocks(api):
|
||||
# Generally fired by utils.
|
||||
myBlock = api.data['block']
|
||||
blockType = api.data['type']
|
||||
logger.info('blockType is ' + blockType)
|
||||
|
||||
# Process specific block types
|
||||
|
||||
# userInfo blocks, such as for setting username
|
||||
if blockType == 'userInfo':
|
||||
if api.data['validSig'] == True: # we use == True for type safety
|
||||
_processUserInfo(api, myBlock)
|
||||
# forwardKey blocks, add a new forward secrecy key for a peer
|
||||
elif blockType == 'forwardKey':
|
||||
if api.data['validSig'] == True:
|
||||
_processForwardKey(api, myBlock)
|
||||
# socket blocks
|
||||
elif blockType == 'socket':
|
||||
if api.data['validSig'] == True and myBlock.decrypted: # we check if it is decrypted as a way of seeing if it was for us
|
||||
logger.info('Detected socket advertised to us...')
|
||||
try:
|
||||
address = myBlock.getMetadata('address')
|
||||
except KeyError:
|
||||
raise onionrexceptions.MissingAddress("Missing address for new socket")
|
||||
try:
|
||||
port = myBlock.getMetadata('port')
|
||||
except KeyError:
|
||||
raise ValueError("Missing port for new socket")
|
||||
try:
|
||||
reason = myBlock.getMetadata('reason')
|
||||
except KeyError:
|
||||
raise ValueError("Missing socket reason")
|
||||
|
||||
socketInfo = json.dumps({'peer': api.data['signer'], 'address': address, 'port': port, 'create': False, 'reason': reason})
|
||||
api.get_core().daemonQueueAdd('addSocket', socketInfo)
|
||||
else:
|
||||
logger.warn("socket is not for us or is invalid")
|
||||
|
||||
def on_init(api, data = None):
|
||||
|
||||
pluginapi = api
|
||||
|
||||
return
|
|
@ -1,5 +1,5 @@
|
|||
'''
|
||||
Onionr - P2P Microblogging Platform & Social network
|
||||
Onionr - P2P Anonymous Storage Network
|
||||
|
||||
This default plugin handles private messages in an email like fashion
|
||||
'''
|
||||
|
@ -22,9 +22,13 @@
|
|||
import logger, config, threading, time, readline, datetime
|
||||
from onionrblockapi import Block
|
||||
import onionrexceptions, onionrusers
|
||||
import locale
|
||||
import locale, sys, os
|
||||
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
||||
import sentboxdb # import after path insert
|
||||
|
||||
plugin_name = 'pms'
|
||||
PLUGIN_VERSION = '0.0.1'
|
||||
|
||||
|
@ -44,22 +48,23 @@ class MailStrings:
|
|||
self.mailInstance = mailInstance
|
||||
|
||||
self.programTag = 'OnionrMail v%s' % (PLUGIN_VERSION)
|
||||
choices = ['view inbox', 'view sentbox', 'send message', 'help', 'quit']
|
||||
choices = ['view inbox', 'view sentbox', 'send message', 'quit']
|
||||
self.mainMenuChoices = choices
|
||||
self.mainMenu = '''\n
|
||||
-----------------
|
||||
1. %s
|
||||
2. %s
|
||||
3. %s
|
||||
4. %s
|
||||
5. %s''' % (choices[0], choices[1], choices[2], choices[3], choices[4])
|
||||
4. %s''' % (choices[0], choices[1], choices[2], choices[3])
|
||||
|
||||
class OnionrMail:
|
||||
def __init__(self, pluginapi):
|
||||
self.myCore = pluginapi.get_core()
|
||||
#self.dataFolder = pluginapi.get_data_folder()
|
||||
self.strings = MailStrings(self)
|
||||
|
||||
self.sentboxTools = sentboxdb.SentBox(self.myCore)
|
||||
self.sentboxList = []
|
||||
self.sentMessages = {}
|
||||
return
|
||||
|
||||
def inbox(self):
|
||||
|
@ -68,6 +73,7 @@ class OnionrMail:
|
|||
pmBlocks = {}
|
||||
logger.info('Decrypting messages...')
|
||||
choice = ''
|
||||
displayList = []
|
||||
|
||||
# this could use a lot of memory if someone has recieved a lot of messages
|
||||
for blockHash in self.myCore.getBlocksByType('pm'):
|
||||
|
@ -93,8 +99,10 @@ class OnionrMail:
|
|||
senderDisplay = senderKey
|
||||
|
||||
blockDate = pmBlocks[blockHash].getDate().strftime("%m/%d %H:%M")
|
||||
print('%s. %s - %s: %s' % (blockCount, blockDate, senderDisplay[:12], blockHash))
|
||||
|
||||
displayList.append('%s. %s - %s: %s' % (blockCount, blockDate, senderDisplay[:12], blockHash))
|
||||
#displayList.reverse()
|
||||
for i in displayList:
|
||||
print(i)
|
||||
try:
|
||||
choice = logger.readline('Enter a block number, -r to refresh, or -q to stop: ').strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
|
@ -121,15 +129,52 @@ class OnionrMail:
|
|||
else:
|
||||
cancel = ''
|
||||
readBlock.verifySig()
|
||||
print('Message recieved from %s' % (readBlock.signer,))
|
||||
print('Message recieved from %s' % (self.myCore._utils.bytesToStr(readBlock.signer,)))
|
||||
print('Valid signature:', readBlock.validSig)
|
||||
if not readBlock.validSig:
|
||||
logger.warn('This message has an INVALID signature. ANYONE could have sent this message.')
|
||||
cancel = logger.readline('Press enter to continue to message, or -q to not open the message (recommended).')
|
||||
if cancel != '-q':
|
||||
print(draw_border(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode().strip())))
|
||||
input("Press enter to continue")
|
||||
return
|
||||
|
||||
def sentbox(self):
|
||||
'''
|
||||
Display sent mail messages
|
||||
'''
|
||||
entering = True
|
||||
while entering:
|
||||
self.getSentList()
|
||||
print('Enter block number or -q to return')
|
||||
try:
|
||||
choice = input('>')
|
||||
except (EOFError, KeyboardInterrupt) as e:
|
||||
entering = False
|
||||
else:
|
||||
if choice == '-q':
|
||||
entering = False
|
||||
else:
|
||||
try:
|
||||
self.sentboxList[int(choice) - 1]
|
||||
except IndexError:
|
||||
print('Invalid block')
|
||||
else:
|
||||
logger.info('Sent to: ' + self.sentMessages[self.sentboxList[int(choice) - 1]][1])
|
||||
# Print ansi escaped sent message
|
||||
print(self.myCore._utils.escapeAnsi(self.sentMessages[self.sentboxList[int(choice) - 1]][0]))
|
||||
input('Press enter to continue...')
|
||||
|
||||
return
|
||||
|
||||
def getSentList(self):
|
||||
count = 1
|
||||
for i in self.sentboxTools.listSent():
|
||||
self.sentboxList.append(i['hash'])
|
||||
self.sentMessages[i['hash']] = (i['message'], i['peer'])
|
||||
print('%s. %s - %s - %s' % (count, i['hash'], i['peer'][:12], i['date']))
|
||||
count += 1
|
||||
|
||||
def draftMessage(self):
|
||||
message = ''
|
||||
newLine = ''
|
||||
|
@ -166,8 +211,8 @@ class OnionrMail:
|
|||
|
||||
print('Inserting encrypted message as Onionr block....')
|
||||
|
||||
self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip, sign=True)
|
||||
|
||||
blockID = self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip, sign=True)
|
||||
self.sentboxTools.addToSent(blockID, recip, message)
|
||||
def menu(self):
|
||||
choice = ''
|
||||
while True:
|
||||
|
@ -182,12 +227,10 @@ class OnionrMail:
|
|||
if choice in (self.strings.mainMenuChoices[0], '1'):
|
||||
self.inbox()
|
||||
elif choice in (self.strings.mainMenuChoices[1], '2'):
|
||||
logger.warn('not implemented yet')
|
||||
self.sentbox()
|
||||
elif choice in (self.strings.mainMenuChoices[2], '3'):
|
||||
self.draftMessage()
|
||||
elif choice in (self.strings.mainMenuChoices[3], '4'):
|
||||
logger.warn('not implemented yet')
|
||||
elif choice in (self.strings.mainMenuChoices[4], '5'):
|
||||
logger.info('Goodbye.')
|
||||
break
|
||||
elif choice == '':
|
||||
|
|
62
onionr/static-data/default-plugins/pms/sentboxdb.py
Normal file
62
onionr/static-data/default-plugins/pms/sentboxdb.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
'''
|
||||
Onionr - P2P Microblogging Platform & Social network
|
||||
|
||||
This file handles the sentbox for the mail plugin
|
||||
'''
|
||||
'''
|
||||
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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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, os
|
||||
import core
|
||||
class SentBox:
|
||||
def __init__(self, mycore):
|
||||
assert isinstance(mycore, core.Core)
|
||||
self.dbLocation = mycore.dataDir + 'sentbox.db'
|
||||
if not os.path.exists(self.dbLocation):
|
||||
self.createDB()
|
||||
self.conn = sqlite3.connect(self.dbLocation)
|
||||
self.cursor = self.conn.cursor()
|
||||
self.core = mycore
|
||||
return
|
||||
|
||||
def createDB(self):
|
||||
conn = sqlite3.connect(self.dbLocation)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''CREATE TABLE sent(
|
||||
hash id not null,
|
||||
peer text not null,
|
||||
message text not null,
|
||||
date int not null
|
||||
);
|
||||
''')
|
||||
conn.commit()
|
||||
return
|
||||
|
||||
def listSent(self):
|
||||
retData = []
|
||||
for entry in self.cursor.execute('SELECT * FROM sent;'):
|
||||
retData.append({'hash': entry[0], 'peer': entry[1], 'message': entry[2], 'date': entry[3]})
|
||||
return retData
|
||||
|
||||
def addToSent(self, blockID, peer, message):
|
||||
args = (blockID, peer, message, self.core._utils.getEpoch())
|
||||
self.cursor.execute('INSERT INTO sent VALUES(?, ?, ?, ?)', args)
|
||||
self.conn.commit()
|
||||
return
|
||||
|
||||
def removeSent(self, blockID):
|
||||
args = (blockID,)
|
||||
self.cursor.execute('DELETE FROM sent where hash=?', args)
|
||||
self.conn.commit()
|
||||
return
|
|
@ -2,6 +2,8 @@
|
|||
"general" : {
|
||||
"dev_mode" : true,
|
||||
"display_header" : true,
|
||||
"minimum_block_pow": 5,
|
||||
"minimum_send_pow": 5,
|
||||
|
||||
"direct_connect" : {
|
||||
"respond" : true,
|
||||
|
@ -32,11 +34,10 @@
|
|||
"client" : {
|
||||
|
||||
},
|
||||
|
||||
"log" : {
|
||||
"file" : {
|
||||
"output" : true,
|
||||
"path" : "data/output.log"
|
||||
"log": {
|
||||
"file": {
|
||||
"output": false,
|
||||
"path": "data/output.log"
|
||||
},
|
||||
|
||||
"console" : {
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
<p>The content on this server is not necessarily created by the server owner, and was not necessarily stored specifically with the owner's knowledge of its contents.</p>
|
||||
|
||||
<p>Onionr is a decentralized, distributed data storage system, that anyone can insert data into.</p>
|
||||
<p>Onionr is a decentralized data storage system that anyone can insert data into.</p>
|
||||
|
||||
<p>To learn more about Onionr, see the website at <a href="https://onionr.voidnet.tech/">https://Onionr.VoidNet.tech/</a></p>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue