2020-08-19 13:01:37 +00:00
|
|
|
import os,time,sys,logging
|
2020-08-17 13:33:26 +00:00
|
|
|
from pathlib import Path
|
2020-08-20 00:34:14 +00:00
|
|
|
import asyncio,time
|
2020-08-19 13:01:37 +00:00
|
|
|
# handler = logging.StreamHandler()
|
|
|
|
# formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
# handler.setFormatter(formatter)
|
|
|
|
# logger = logging.getLogger(__file__)
|
|
|
|
# logger.addHandler(handler)
|
|
|
|
# logger.setLevel(logging.DEBUG)
|
|
|
|
sys.path.append('../p2p')
|
|
|
|
# logger.info(os.getcwd(), sys.path)
|
2020-08-20 01:39:26 +00:00
|
|
|
BSEP=b'||||'
|
2020-08-19 13:01:37 +00:00
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
try:
|
|
|
|
from .crypto import *
|
|
|
|
from .p2p import *
|
|
|
|
from .kad import *
|
2020-08-19 13:01:37 +00:00
|
|
|
except ModuleNotFoundError:
|
2020-08-19 12:06:44 +00:00
|
|
|
from crypto import *
|
|
|
|
from p2p import *
|
|
|
|
from kad import KadServer
|
2020-08-17 20:40:48 +00:00
|
|
|
from pathlib import Path
|
|
|
|
from functools import partial
|
2020-08-17 13:33:26 +00:00
|
|
|
|
|
|
|
# works better with tor?
|
|
|
|
import json
|
|
|
|
jsonify = json.dumps
|
2020-08-19 10:29:56 +00:00
|
|
|
|
2020-08-17 13:33:26 +00:00
|
|
|
# Start server
|
|
|
|
|
|
|
|
DEBUG = True
|
|
|
|
UPLOAD_DIR = 'uploads/'
|
|
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
2020-08-19 10:29:56 +00:00
|
|
|
|
2020-08-18 15:14:19 +00:00
|
|
|
# PORT_SPEAK = 8468
|
2020-08-19 14:07:12 +00:00
|
|
|
PORT_LISTEN = 5639
|
2020-08-17 13:33:26 +00:00
|
|
|
|
|
|
|
# Api Functions
|
2020-08-18 14:32:10 +00:00
|
|
|
from threading import Thread
|
|
|
|
|
|
|
|
def start_selfless_thread():
|
|
|
|
async def _go():
|
|
|
|
loop=asyncio.get_event_loop()
|
|
|
|
return boot_selfless_node(port=PORT_SPEAK, loop=loop)
|
|
|
|
return asyncio.run(_go())
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
async def _getdb(self=None,port=PORT_LISTEN):
|
|
|
|
|
|
|
|
if self: self.log('starting server..')
|
2020-08-19 15:13:49 +00:00
|
|
|
|
|
|
|
import os
|
|
|
|
self.log(os.getcwd())
|
|
|
|
node = KadServer(storage=HalfForgetfulStorage(fn='../p2p/cache.sqlite'))
|
2020-08-19 11:30:23 +00:00
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
if self: self.log('listening..')
|
2020-08-19 11:30:23 +00:00
|
|
|
await node.listen(port)
|
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
if self: self.log('bootstrapping server..')
|
2020-08-19 11:30:23 +00:00
|
|
|
await node.bootstrap(NODES_PRIME)
|
|
|
|
return node
|
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
def logg(x):
|
|
|
|
print(x)
|
|
|
|
|
2020-08-17 16:23:40 +00:00
|
|
|
class Api(object):
|
2020-08-19 12:06:44 +00:00
|
|
|
def __init__(self,app = None):
|
2020-08-19 10:29:56 +00:00
|
|
|
self.app=app
|
2020-08-19 12:06:44 +00:00
|
|
|
self.app_storage = self.app.store if app else {}
|
|
|
|
self.log = self.app.log if app else logg
|
2020-08-18 17:25:15 +00:00
|
|
|
|
2020-08-19 10:29:56 +00:00
|
|
|
# self.log('starting selfless daemon...')
|
2020-08-18 15:00:14 +00:00
|
|
|
# self.selfless = Thread(target=start_selfless_thread)
|
|
|
|
# self.selfless.daemon = True
|
|
|
|
# self.selfless.start()
|
2020-08-19 10:29:56 +00:00
|
|
|
|
|
|
|
# connect?
|
2020-08-19 13:01:37 +00:00
|
|
|
#self._node=self.connect()
|
2020-08-17 16:23:40 +00:00
|
|
|
pass
|
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def connect_forever(self):
|
|
|
|
try:
|
|
|
|
i = 0
|
|
|
|
self._node = await self.connect()
|
|
|
|
while True:
|
2020-08-19 19:33:25 +00:00
|
|
|
self.log(f'Node status (minute {i}): {self._node}')
|
2020-08-19 14:07:12 +00:00
|
|
|
|
|
|
|
# # get some sleep
|
|
|
|
# if self.root.ids.btn1.state != 'down' and i >= 2:
|
|
|
|
# i = 0
|
|
|
|
# self.log('Yawn, getting tired. Going to sleep')
|
|
|
|
# self.root.ids.btn1.trigger_action()
|
|
|
|
|
2020-08-20 01:39:26 +00:00
|
|
|
i += 1
|
2020-08-19 19:33:25 +00:00
|
|
|
await asyncio.sleep(60)
|
|
|
|
# pass
|
2020-08-19 14:07:12 +00:00
|
|
|
except asyncio.CancelledError as e:
|
|
|
|
self.log('Wasting time was canceled', e)
|
|
|
|
finally:
|
|
|
|
# when canceled, print that it finished
|
|
|
|
self.log('Done wasting time')
|
|
|
|
|
|
|
|
@property
|
|
|
|
async def node(self):
|
|
|
|
if not hasattr(self,'_node'):
|
|
|
|
self._node=await self.connect()
|
|
|
|
return self._node
|
|
|
|
|
|
|
|
async def connect(self,port=PORT_LISTEN):
|
|
|
|
self.log('connecting...')
|
|
|
|
return await _getdb(self,port)
|
|
|
|
|
|
|
|
|
|
|
|
async def get(self,key_or_keys):
|
2020-08-18 09:01:22 +00:00
|
|
|
|
2020-08-17 16:23:40 +00:00
|
|
|
async def _get():
|
2020-08-19 11:14:52 +00:00
|
|
|
# self.log('async _get()',self.node)
|
2020-08-19 14:07:12 +00:00
|
|
|
#node=await _getdb(self)
|
|
|
|
node=await self.node
|
2020-08-18 14:52:20 +00:00
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
if type(key_or_keys) in {list,tuple,dict}:
|
|
|
|
keys = key_or_keys
|
2020-08-20 01:39:26 +00:00
|
|
|
res = await asyncio.gather(*[self.unpack_well_documented_val(await node.get(key)) for key in keys])
|
2020-08-17 22:06:31 +00:00
|
|
|
#log('RES?',res)
|
2020-08-17 20:40:48 +00:00
|
|
|
else:
|
|
|
|
key = key_or_keys
|
2020-08-20 01:39:26 +00:00
|
|
|
res = await self.unpack_well_documented_val(await node.get(key))
|
2020-08-17 20:40:48 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
#node.stop()
|
2020-08-17 20:40:48 +00:00
|
|
|
return res
|
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
return await _get()
|
2020-08-20 00:34:14 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
def well_documented_val(self,val,sep=BSEP,do_encrypt=True,receiver_pubkey=None):
|
2020-08-20 00:34:14 +00:00
|
|
|
"""
|
|
|
|
What do we want to store with
|
|
|
|
|
|
|
|
1) Timestamp
|
|
|
|
2) Value
|
|
|
|
3) Public key of author
|
|
|
|
4) Signature of value by author
|
|
|
|
"""
|
2020-08-20 08:55:50 +00:00
|
|
|
import time
|
2020-08-20 00:34:14 +00:00
|
|
|
timestamp=time.time()
|
|
|
|
self.log('timestamp =',timestamp)
|
|
|
|
|
2020-08-20 01:39:26 +00:00
|
|
|
if type(val)!=bytes:
|
|
|
|
value = str(val)
|
|
|
|
try:
|
|
|
|
value_bytes = value.encode('utf-8')
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
value_bytes = value.encode('ascii')
|
|
|
|
else:
|
|
|
|
value_bytes=val
|
|
|
|
|
|
|
|
|
|
|
|
# encrypt?
|
2020-08-20 08:55:50 +00:00
|
|
|
if not receiver_pubkey: receiver_pubkey=self.public_key_global
|
|
|
|
# self.log('value while unencrypted =',value_bytes)
|
|
|
|
|
|
|
|
# value_bytes = encrypt_msg(value_bytes, self.public_key_global)
|
|
|
|
|
|
|
|
res = encrypt(value_bytes, self.private_key, receiver_pubkey)
|
|
|
|
|
2020-08-20 00:34:14 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
#aes_ciphertext, encry_aes_key, hmac, hmac_signature, iv, metadata
|
|
|
|
|
|
|
|
self.log('value while encrypted = ',res)
|
|
|
|
# stop
|
|
|
|
aes_ciphertext, encry_aes_key, iv = res
|
2020-08-20 00:34:14 +00:00
|
|
|
#self.log('value =',value)
|
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
pem_public_key = serialize_pubkey(receiver_pubkey)
|
2020-08-20 00:34:14 +00:00
|
|
|
|
|
|
|
#self.log('pem_public_key =',pem_public_key)
|
|
|
|
# stop
|
2020-08-20 08:55:50 +00:00
|
|
|
self.log('aes_ciphertext = ',aes_ciphertext,type(aes_ciphertext))
|
2020-08-20 00:34:14 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
signature = sign(aes_ciphertext, self.private_key)
|
2020-08-20 00:34:14 +00:00
|
|
|
self.log('signature =',signature)
|
|
|
|
|
2020-08-20 01:39:26 +00:00
|
|
|
## Verify!
|
2020-08-20 08:55:50 +00:00
|
|
|
authentic = verify_signature(signature, aes_ciphertext, self.public_key)
|
2020-08-20 01:39:26 +00:00
|
|
|
self.log('message is authentic for set??',authentic)
|
|
|
|
|
2020-08-20 00:34:14 +00:00
|
|
|
# value_bytes_ascii = ''.join([chr(x) for x in value_bytes])
|
|
|
|
|
|
|
|
# jsond = {'time':timestamp, 'val':value_bytes_ascii, 'pub':pem_public_key, 'sign':signature}
|
|
|
|
# jsonstr=jsonify(jsond)
|
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
time_b=str(timestamp).encode()
|
|
|
|
val_encr = aes_ciphertext
|
|
|
|
val_encr_key = encry_aes_key
|
|
|
|
sender_pubkey_b = serialize_pubkey(self.public_key)
|
|
|
|
receiver_pubkey_b = serialize_pubkey(receiver_pubkey)
|
|
|
|
signature = signature
|
|
|
|
|
|
|
|
WDV = sep.join([
|
|
|
|
time_b,
|
|
|
|
val_encr,
|
|
|
|
val_encr_key,
|
|
|
|
iv,
|
|
|
|
receiver_pubkey_b,
|
|
|
|
sender_pubkey_b,
|
|
|
|
signature
|
|
|
|
])
|
|
|
|
|
|
|
|
self.log('well_documented_val() =',WDV)
|
2020-08-20 00:34:14 +00:00
|
|
|
return WDV
|
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
async def unpack_well_documented_val(self,WDV,sep=BSEP,private_key=None):
|
2020-08-20 01:39:26 +00:00
|
|
|
self.log('WDV???',WDV)
|
2020-08-20 08:55:50 +00:00
|
|
|
if WDV is None: return WDV
|
|
|
|
#WDV=[base64.b64decode(x) for x in WDV.split(sep)]
|
|
|
|
WDV=WDV.split(sep)
|
|
|
|
self.log('WDV NEW:',WDV)
|
|
|
|
|
|
|
|
time_b,val_encr,val_encr_key,iv,to_pub_b,from_pub_b,signature = WDV #.split(sep)
|
|
|
|
to_pub = load_pubkey(to_pub_b)
|
|
|
|
from_pub = load_pubkey(from_pub_b)
|
2020-08-20 01:39:26 +00:00
|
|
|
|
|
|
|
# verify
|
2020-08-20 08:55:50 +00:00
|
|
|
|
|
|
|
val_encr_decode = base64.b64decode(val_encr)
|
|
|
|
authentic = verify_signature(signature,val_encr,from_pub)
|
|
|
|
self.log('message is authentic for GET?',authentic,signature,val_encr)
|
2020-08-20 01:39:26 +00:00
|
|
|
|
|
|
|
if not authentic:
|
|
|
|
self.log('inauthentic message!')
|
2020-08-20 08:55:50 +00:00
|
|
|
return {}
|
2020-08-20 01:39:26 +00:00
|
|
|
|
|
|
|
# decrypt
|
2020-08-20 08:55:50 +00:00
|
|
|
# self.log('val before decryption = ',val_encr)
|
|
|
|
if private_key is None: private_key=self.private_key_global
|
|
|
|
val = decrypt(val_encr, val_encr_key, iv, private_key)
|
|
|
|
# self.log('val after decryption = ',val)
|
2020-08-20 01:39:26 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
# time=float(time.decode())
|
2020-08-20 01:39:26 +00:00
|
|
|
#val=val.decode()
|
2020-08-20 08:55:50 +00:00
|
|
|
# return time,val,pub,sign
|
|
|
|
WDV={
|
|
|
|
'time':float(time_b.decode()),
|
|
|
|
'val':val,
|
|
|
|
'to':to_pub,
|
|
|
|
'from':from_pub,
|
|
|
|
'sign':signature
|
|
|
|
}
|
|
|
|
|
|
|
|
self.log('GOT WDV:',WDV)
|
|
|
|
return WDV
|
|
|
|
|
|
|
|
|
|
|
|
#,signature
|
2020-08-20 01:39:26 +00:00
|
|
|
|
2020-08-19 14:27:12 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def set(self,key_or_keys,value_or_values):
|
2020-08-19 14:27:12 +00:00
|
|
|
async def _set():
|
2020-08-19 11:14:52 +00:00
|
|
|
# self.log('async _set()',self.node)
|
2020-08-19 11:30:23 +00:00
|
|
|
# node=self.node
|
2020-08-19 14:07:12 +00:00
|
|
|
#node=await _getdb(self)
|
|
|
|
node=await self.node
|
2020-08-19 13:01:37 +00:00
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
if type(key_or_keys) in {list,tuple,dict}:
|
|
|
|
keys = key_or_keys
|
|
|
|
values = value_or_values
|
|
|
|
assert len(keys)==len(values)
|
2020-08-20 00:34:14 +00:00
|
|
|
res = await asyncio.gather(*[node.set(key,self.well_documented_val(value)) for key,value in zip(keys,values)])
|
2020-08-19 10:29:56 +00:00
|
|
|
# self.log('RES?',res)
|
2020-08-17 20:40:48 +00:00
|
|
|
else:
|
|
|
|
key = key_or_keys
|
|
|
|
value = value_or_values
|
2020-08-20 00:34:14 +00:00
|
|
|
res = await node.set(key,self.well_documented_val(value))
|
2020-08-17 20:40:48 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
#node.stop()
|
2020-08-17 20:40:48 +00:00
|
|
|
return res
|
2020-08-18 17:25:15 +00:00
|
|
|
|
2020-08-19 14:27:12 +00:00
|
|
|
return await _set()
|
2020-08-18 17:25:15 +00:00
|
|
|
|
2020-08-19 14:27:12 +00:00
|
|
|
async def get_json(self,key_or_keys):
|
|
|
|
res = await self.get(key_or_keys)
|
|
|
|
self.log('GET_JSON',res)
|
2020-08-20 08:55:50 +00:00
|
|
|
if res is None: return res
|
|
|
|
|
|
|
|
def jsonize(entry):
|
|
|
|
if not 'val' in entry: return entry
|
|
|
|
val=entry['val']
|
|
|
|
dat=json.loads(val.decode())
|
|
|
|
entry['val']=dat
|
|
|
|
return entry
|
|
|
|
|
2020-08-19 14:27:12 +00:00
|
|
|
if type(res)==list:
|
2020-08-20 08:55:50 +00:00
|
|
|
jsonl=[jsonize(entry) for entry in res]
|
2020-08-20 01:39:26 +00:00
|
|
|
return jsonl
|
2020-08-19 14:27:12 +00:00
|
|
|
else:
|
2020-08-20 08:55:50 +00:00
|
|
|
entry = res
|
|
|
|
return jsonize(entry)
|
2020-08-19 13:01:37 +00:00
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def set_json(self,key,value):
|
2020-08-17 20:40:48 +00:00
|
|
|
value_json = jsonify(value)
|
2020-08-19 10:29:56 +00:00
|
|
|
# self.log('OH NO!',sys.getsizeof(value_json))
|
2020-08-19 14:27:12 +00:00
|
|
|
return await self.set(key,value_json)
|
2020-08-17 16:23:40 +00:00
|
|
|
|
2020-08-19 19:33:25 +00:00
|
|
|
async def has(self,key):
|
|
|
|
val=await self.get(key)
|
|
|
|
return val is not None
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
## PERSONS
|
2020-08-19 19:33:25 +00:00
|
|
|
async def get_person(self,username):
|
2020-08-20 08:55:50 +00:00
|
|
|
res=await self.get_json('/person/'+username)
|
|
|
|
return res.get('val') if res and type(res)==dict else res
|
2020-08-17 16:23:40 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
async def set_person(self,username,pem_public_key):
|
|
|
|
# pem_public_key = save_public_key(public_key,return_instead=True)
|
|
|
|
obj = {'name':username, 'public_key':pem_public_key}
|
2020-08-19 19:33:25 +00:00
|
|
|
await self.set_json('/person/'+username,obj)
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Register
|
2020-08-19 19:33:25 +00:00
|
|
|
async def register(self,name,passkey):
|
|
|
|
if not (name and passkey): return {'error':'Name and password needed'}
|
|
|
|
person = await self.get_person(name)
|
|
|
|
if person is not None: return {'error':'Username already exists'}
|
2020-08-17 16:23:40 +00:00
|
|
|
|
2020-08-20 08:55:50 +00:00
|
|
|
self._private_key = private_key = generate_rsa_key()
|
|
|
|
# self._public_key = public_key = self.private_key.public_key()
|
|
|
|
pem_private_key = serialize_privkey(self.private_key, password=passkey)# save_private_key(private_key,password=passkey,return_instead=True)
|
|
|
|
#pem_public_key = save_public_key(public_key,return_instead=True)
|
|
|
|
pem_public_key = serialize_pubkey(self.public_key)
|
|
|
|
|
|
|
|
await self.set_person(name,pem_public_key.decode())
|
|
|
|
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
self.app_storage.put('_keys',
|
2020-08-20 08:55:50 +00:00
|
|
|
private=pem_private_key.decode(),
|
|
|
|
public=pem_public_key.decode()) #(private_key,password=passkey)
|
2020-08-17 16:23:40 +00:00
|
|
|
return {'success':'Account created', 'username':name}
|
|
|
|
|
2020-08-20 01:39:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-17 16:23:40 +00:00
|
|
|
def load_private_key(self,password):
|
2020-08-19 23:26:25 +00:00
|
|
|
if not self.app_storage.exists('_keys'): return {'error':'No login keys present on this device'}
|
2020-08-17 16:23:40 +00:00
|
|
|
pem_private_key=self.app_storage.get('_keys').get('private')
|
2020-08-20 08:55:50 +00:00
|
|
|
self.log('my private key ====',pem_private_key)
|
2020-08-17 16:23:40 +00:00
|
|
|
try:
|
2020-08-20 08:55:50 +00:00
|
|
|
return {'success':load_privkey(pem_private_key,password)}
|
2020-08-17 16:23:40 +00:00
|
|
|
except ValueError as e:
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('!!',e)
|
2020-08-19 20:15:38 +00:00
|
|
|
return {'error':'Incorrect password'}
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## LOGIN
|
2020-08-19 19:33:25 +00:00
|
|
|
async def login(self,name,passkey):
|
2020-08-17 16:23:40 +00:00
|
|
|
# verify input
|
|
|
|
if not (name and passkey):
|
|
|
|
return {'error':'Name and password required'}
|
|
|
|
|
|
|
|
# try to load private key
|
2020-08-19 19:33:25 +00:00
|
|
|
private_key_dat = self.load_private_key(passkey)
|
|
|
|
if 'error' in private_key_dat:
|
|
|
|
return {'error':private_key_dat['error']}
|
|
|
|
if not 'success' in private_key_dat:
|
|
|
|
return {'error':'Incorrect password?'}
|
2020-08-20 00:34:14 +00:00
|
|
|
self._private_key = private_key = private_key_dat['success']
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
# see if user exists
|
2020-08-19 19:33:25 +00:00
|
|
|
person = await self.get_person(name)
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log(person)
|
2020-08-17 16:23:40 +00:00
|
|
|
if person is None:
|
|
|
|
return {'error':'Login failed'}
|
|
|
|
|
|
|
|
# verify keys
|
|
|
|
person_public_key_pem = person['public_key']
|
2020-08-20 08:55:50 +00:00
|
|
|
public_key = load_pubkey(person_public_key_pem) #load_public_key(person_public_key_pem.encode())
|
2020-08-20 00:34:14 +00:00
|
|
|
self._public_key = real_public_key = private_key.public_key()
|
2020-08-17 16:23:40 +00:00
|
|
|
|
|
|
|
#log('PUBLIC',public_key.public_numbers())
|
|
|
|
#log('REAL PUBLIC',real_public_key.public_numbers())
|
|
|
|
|
|
|
|
if public_key.public_numbers() != real_public_key.public_numbers():
|
2020-08-19 19:33:25 +00:00
|
|
|
return {'error':'Keys do not match!'}
|
2020-08-17 16:23:40 +00:00
|
|
|
return {'success':'Login successful', 'username':name}
|
|
|
|
|
2020-08-20 00:34:14 +00:00
|
|
|
@property
|
|
|
|
def public_key(self):
|
|
|
|
if not hasattr(self,'_public_key'):
|
2020-08-20 08:55:50 +00:00
|
|
|
if not hasattr(self,'_private_key'):
|
|
|
|
self.app.root.change_screen('login')
|
|
|
|
else:
|
|
|
|
self._public_key=self.private_key.public_key()
|
2020-08-20 00:34:14 +00:00
|
|
|
return self._public_key
|
|
|
|
|
|
|
|
@property
|
|
|
|
def private_key(self):
|
|
|
|
if not hasattr(self,'_private_key'):
|
|
|
|
self.app.root.change_screen('login')
|
|
|
|
return self._private_key
|
|
|
|
|
2020-08-20 01:39:26 +00:00
|
|
|
@property
|
|
|
|
def public_key_global(self):
|
|
|
|
if not hasattr(self,'_public_key_global'):
|
|
|
|
try:
|
|
|
|
pem=self.app.store_global.get('_keys').get('public',None)
|
|
|
|
self._public_key_global=load_public_key(pem.encode())
|
|
|
|
return self._public_key_global
|
|
|
|
except ValueError as e:
|
|
|
|
self.log('!!',e)
|
|
|
|
return None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def private_key_global(self):
|
|
|
|
if not hasattr(self,'_private_key_global'):
|
|
|
|
try:
|
|
|
|
pem=self.app.store_global.get('_keys').get('private',None)
|
|
|
|
self._private_key_global=load_private_key(pem.encode())
|
|
|
|
return self._private_key_global
|
|
|
|
except ValueError as e:
|
|
|
|
self.log('!!',e)
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def append_json(self,key,data):
|
|
|
|
sofar=await self.get_json(key)
|
2020-08-17 20:40:48 +00:00
|
|
|
if sofar is None: sofar = []
|
|
|
|
new=sofar + ([data] if type(data)!=list else data)
|
2020-08-19 14:07:12 +00:00
|
|
|
if await self.set_json(key, new):
|
2020-08-17 20:40:48 +00:00
|
|
|
return {'success':'Length increased to %s' % len(new)}
|
|
|
|
return {'error':'Could not append json'}
|
|
|
|
|
2020-08-19 19:33:25 +00:00
|
|
|
async def upload(self,filename,file_id=None, uri='/file/',uri_part='/part/'):
|
2020-08-17 20:40:48 +00:00
|
|
|
import sys
|
|
|
|
|
|
|
|
if not file_id: file_id = get_random_id()
|
|
|
|
part_ids = []
|
|
|
|
part_keys = []
|
|
|
|
parts=[]
|
|
|
|
PARTS=[]
|
|
|
|
buffer_size=100
|
|
|
|
for part in bytes_from_file(filename,chunksize=1024*7):
|
|
|
|
part_id = get_random_id()
|
|
|
|
part_ids.append(part_id)
|
|
|
|
part_key='/part/'+part_id
|
|
|
|
part_keys.append(part_key)
|
|
|
|
parts.append(part)
|
|
|
|
# PARTS.append(part)
|
|
|
|
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('part!:',sys.getsizeof(part))
|
2020-08-17 20:40:48 +00:00
|
|
|
#self.set(part_key,part)
|
|
|
|
|
|
|
|
if len(parts)>=buffer_size:
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('setting...')
|
2020-08-19 19:33:25 +00:00
|
|
|
await self.set(part_keys,parts)
|
2020-08-17 20:40:48 +00:00
|
|
|
part_keys=[]
|
|
|
|
PARTS+=parts
|
|
|
|
parts=[]
|
|
|
|
|
|
|
|
# set all parts
|
|
|
|
#self.set(part_keys,PARTS)
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('# parts:',len(PARTS))
|
2020-08-19 19:33:25 +00:00
|
|
|
if parts and part_keys: await self.set(part_keys, parts)
|
2020-08-17 20:40:48 +00:00
|
|
|
|
|
|
|
# how many parts?
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('# pieces!',len(part_ids))
|
2020-08-17 20:40:48 +00:00
|
|
|
|
|
|
|
file_store = {'ext':os.path.splitext(filename)[-1][1:], 'parts':part_ids}
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('FILE STORE??',file_store)
|
2020-08-19 19:33:25 +00:00
|
|
|
await self.set_json(uri+file_id,file_store)
|
2020-08-17 20:40:48 +00:00
|
|
|
|
|
|
|
# file_store['data'].seek(0)
|
|
|
|
file_store['id']=file_id
|
|
|
|
return file_store
|
2020-08-17 16:23:40 +00:00
|
|
|
|
2020-08-19 19:33:25 +00:00
|
|
|
async def download(self,file_id):
|
|
|
|
file_store = await self.get_json('/file/'+file_id)
|
2020-08-17 22:06:31 +00:00
|
|
|
if file_store is None: return
|
|
|
|
|
2020-08-19 10:29:56 +00:00
|
|
|
self.log('file_store!?',file_store)
|
2020-08-17 22:06:31 +00:00
|
|
|
keys = ['/part/'+x for x in file_store['parts']]
|
2020-08-20 01:39:26 +00:00
|
|
|
time,pieces,pub,sign = await self.get(keys)
|
2020-08-17 22:06:31 +00:00
|
|
|
file_store['parts_data']=pieces
|
|
|
|
return file_store
|
|
|
|
|
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def post(self,data):
|
2020-08-17 20:40:48 +00:00
|
|
|
post_id=get_random_id()
|
2020-08-19 14:07:12 +00:00
|
|
|
res = await self.set_json('/post/'+post_id, data)
|
2020-08-19 11:14:52 +00:00
|
|
|
self.log('Api.post() got data back from set_json():',res)
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-19 11:14:52 +00:00
|
|
|
# ## add to channels
|
2020-08-19 14:27:12 +00:00
|
|
|
await self.append_json('/posts/channel/earth', post_id)
|
2020-08-17 20:40:48 +00:00
|
|
|
|
2020-08-19 11:14:52 +00:00
|
|
|
# ## add to user
|
2020-08-19 13:01:37 +00:00
|
|
|
un=data.get('author')
|
2020-08-19 14:27:12 +00:00
|
|
|
if un: await self.append_json('/posts/author/'+un, post_id)
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
if res:
|
|
|
|
return {'success':'Posted! %s' % post_id, 'post_id':post_id}
|
|
|
|
return {'error':'Post failed'}
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def get_post(self,post_id):
|
2020-08-17 20:40:48 +00:00
|
|
|
return self.get_json('/post/'+post_id)
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-19 14:07:12 +00:00
|
|
|
async def get_posts(self,uri='/channel/earth'):
|
|
|
|
index = await self.get_json('/posts'+uri)
|
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
if index is None: return []
|
|
|
|
data = self.get_json(['/post/'+x for x in index])
|
2020-08-19 14:07:12 +00:00
|
|
|
|
|
|
|
return await data
|
2020-08-17 13:33:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-19 19:33:25 +00:00
|
|
|
## func
|
|
|
|
|
|
|
|
def bytes_from_file(filename,chunksize=8192):
|
|
|
|
with open(filename, 'rb') as f:
|
|
|
|
while True:
|
|
|
|
piece = f.read(chunksize)
|
|
|
|
if not piece:
|
|
|
|
break
|
|
|
|
yield piece
|
2020-08-17 13:33:26 +00:00
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
def get_random_id():
|
|
|
|
import uuid
|
|
|
|
return uuid.uuid4().hex
|
|
|
|
|
2020-08-17 13:33:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-17 20:40:48 +00:00
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
|
2020-08-19 13:01:37 +00:00
|
|
|
def test_api():
|
|
|
|
api = Api()
|
|
|
|
# api.set(['a','b','c'],[1,2,3])
|
|
|
|
api.set_json('whattttt',{'aaaaa':12222})
|
|
|
|
|
|
|
|
def test_basic():
|
|
|
|
import asyncio
|
|
|
|
from kademlia.network import Server
|
2020-08-19 12:06:44 +00:00
|
|
|
|
2020-08-19 12:11:48 +00:00
|
|
|
#api = Api()
|
2020-08-19 12:06:44 +00:00
|
|
|
|
|
|
|
# not working!
|
2020-08-19 12:11:48 +00:00
|
|
|
#api.set_json('my key',{'a':'value'})
|
2020-08-19 12:06:44 +00:00
|
|
|
|
2020-08-19 13:01:37 +00:00
|
|
|
async def run():
|
|
|
|
# Create a node and start listening on port 5678
|
|
|
|
node = Server()
|
|
|
|
await node.listen(5678)
|
|
|
|
|
|
|
|
# Bootstrap the node by connecting to other known nodes, in this case
|
|
|
|
# replace 123.123.123.123 with the IP of another node and optionally
|
|
|
|
# give as many ip/port combos as you can for other nodes.
|
|
|
|
await node.bootstrap(NODES_PRIME)
|
|
|
|
|
|
|
|
# set a value for the key "my-key" on the network
|
|
|
|
await node.set("my-key", "my awesome value")
|
|
|
|
|
|
|
|
# get the value associated with "my-key" from the network
|
|
|
|
result = await node.get("my-key")
|
|
|
|
|
|
|
|
print(result)
|
|
|
|
return result
|
|
|
|
|
|
|
|
res = asyncio.run(run())
|
|
|
|
print('res = ',res)
|
|
|
|
# res = asyncio.run(node.set(key,value))
|
|
|
|
# print(res)
|
|
|
|
|
|
|
|
def test_provided_eg():
|
|
|
|
import asyncio
|
|
|
|
from kademlia.network import Server
|
|
|
|
|
|
|
|
async def run():
|
|
|
|
# Create a node and start listening on port 5678
|
|
|
|
node = Server()
|
|
|
|
await node.listen(5678)
|
|
|
|
|
|
|
|
# Bootstrap the node by connecting to other known nodes, in this case
|
|
|
|
# replace 123.123.123.123 with the IP of another node and optionally
|
|
|
|
# give as many ip/port combos as you can for other nodes.
|
|
|
|
await node.bootstrap(NODES_PRIME)
|
|
|
|
|
|
|
|
# set a value for the key "my-key" on the network
|
|
|
|
await node.set("my-key", "my awesome value")
|
|
|
|
|
|
|
|
# get the value associated with "my-key" from the network
|
|
|
|
result = await node.get("my-key")
|
|
|
|
|
|
|
|
print(result)
|
|
|
|
|
|
|
|
asyncio.run(run())
|
|
|
|
|
2020-08-19 12:06:44 +00:00
|
|
|
|
|
|
|
if __name__=='__main__':
|
2020-08-19 13:01:37 +00:00
|
|
|
test_api()
|