You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Comrad/comrad/backend/the_operator.py

918 lines
30 KiB
Python

4 years ago
"""
There is only one operator!
Running on node prime.
"""
# internal imports
import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
from comrad import *
from comrad.backend import *
from comrad.backend.messages import Message
4 years ago
# print(PATH_OPERATOR_WEB_KEYS_URL)
4 years ago
# def TheOperator(*x,**y):
# from comrad.backend.operators import Comrad
# return Comrad(OPERATOR_NAME,*x,**y)
4 years ago
class TheOperator(Operator):
"""
4 years ago
The remote operator
4 years ago
"""
4 years ago
@property
def phone(self):
4 years ago
global TELEPHONE
from comrad.backend.the_telephone import TheTelephone
4 years ago
if not TELEPHONE: TELEPHONE=TheTelephone()
4 years ago
return TELEPHONE
4 years ago
4 years ago
def __init__(self, name = OPERATOR_NAME, passphrase=None, callbacks={}):
4 years ago
"""
Boot up the operator. Requires knowing or setting a password of memory.
"""
4 years ago
4 years ago
super().__init__(
name,
path_crypt_keys=PATH_CRYPT_OP_KEYS,
4 years ago
path_crypt_data=PATH_CRYPT_OP_DATA,
callbacks=callbacks
4 years ago
)
from comrad.backend.phonelines import check_phonelines
4 years ago
keychain = check_phonelines()[OPERATOR_NAME]
4 years ago
self._keychain = {**self.load_keychain_from_bytes(keychain)}
4 years ago
4 years ago
if not keychain.get('pubkey'):
raise ComradException('Operator cannot find its own public key? Shutting down.')
4 years ago
# check I match what's on op page
# pub_web = comrad_request(PATH_OPERATOR_WEB_KEYS_URL)
4 years ago
# if pub_web.status_code!=200:
# raise ComradException("Can't verify Comrad Operator. Shutting down.")
# print('Public key on comrad.app/pub: ',pub_web.text)
4 years ago
# print('Public key hardcoded in client: ',keychain.get('pubkey').data_b64_s)
4 years ago
# if pub_web.text == keychain.get('pubkey').data_b64_s:
# # print('Pubs match')
# pass
# else:
# raise ComradException('Public key for Operator on app and one at {PATH_OPERATOR_WEB_KEYS_URL} do not match. Shutting down.')
4 years ago
4 years ago
if os.path.exists(PATH_SUPER_SECRET_OP_KEY):
4 years ago
print('Dare I claim to be the one true Operator?')
with open(PATH_SUPER_SECRET_OP_KEY,'rb') as f:
4 years ago
#pass_encr=f.read()
4 years ago
privkey_decr,privkey_encr,wk1,wk2 = b64dec(f.read()).split(BSEP)
privkey_decr_obj = ComradSymmetricKeyWithoutPassphrase(privkey_decr)
privkey_encr_obj = ComradEncryptedAsymmetricPrivateKey(privkey_encr)
4 years ago
self._keychain['privkey_decr']=privkey_decr_obj
self._keychain['privkey_encr']=privkey_encr_obj
4 years ago
self._keychain = {**self.keychain()}
4 years ago
# self.log('@Operator booted with keychain:',dict_format(self._keychain))
4 years ago
# clear_screen()
4 years ago
4 years ago
4 years ago
4 years ago
def ring(self,
4 years ago
from_caller=None,
to_caller=None,
json_phone2phone={},
json_caller2phone={}, # (person) -> operator or operator -> (person)
json_caller2caller={}):
4 years ago
encr_msg_to_send = super().ring(
4 years ago
from_phone=self,
to_phone=self.phone,
from_caller=from_caller,
to_caller=to_caller,
json_phone2phone=json_phone2phone,
json_caller2phone=json_caller2phone, # (person) -> operator
json_caller2caller=json_caller2caller)
return self.send(encr_msg_to_send)
4 years ago
# ends the ring_ring() chain
4 years ago
def answer_phone(self,data_b):
4 years ago
# route incoming call from the switchboard
from comrad.cli.artcode import ART_OLDPHONE4
4 years ago
4 years ago
4 years ago
self.log(f'''Hello, this is the Operator.{ART_OLDPHONE4}I heard you say:\n\n {b64enc_s(data_b)}''')
4 years ago
#woops
4 years ago
# unseal
4 years ago
# self.log('got:',data_b)
4 years ago
msg_d = {
4 years ago
'msg':data_b,
4 years ago
'from_name':self.phone.name,
4 years ago
'from':self.phone.pubkey.data,
'to_name':self.name,
'to':self.pubkey.data,
4 years ago
}
# msg_d = pickle.loads(data_b)
4 years ago
# self.log('msg_d',msg_d)
4 years ago
msg_obj = Message(msg_d)
4 years ago
4 years ago
# self.log(f'Decoding the binary, I discovered an encrypted message from {self.phone}\n: {msg_obj}')
4 years ago
4 years ago
# decrypt?
msg_obj.decrypt()
4 years ago
# carry out message instructions
4 years ago
resp_msg_obj = self.route_msg(msg_obj,reencrypt=True) #,route=msg_obj.route)
4 years ago
self.log('Response from message routing:',resp_msg_obj)
4 years ago
# send back down encrypted
4 years ago
# self.log('route msgd',dict_format(resp_msg_obj.msg_d))
# self.log('route msg',resp_msg_obj.msg)
4 years ago
# self.log('route msg data',resp_msg_obj.data)
4 years ago
# self.log('route msg obj',resp_msg_obj)
4 years ago
4 years ago
4 years ago
msg_sealed = pickle.dumps(resp_msg_obj.msg_d)
4 years ago
# self.log('msg_sealed =',msg_sealed)
4 years ago
# return back to phone and back down to chain
return msg_sealed
4 years ago
def has_user(self,name=None,pubkey=None):
4 years ago
nm,pk = name,pubkey
if pubkey: pk=self.crypt_keys.get(
4 years ago
name,
prefix='/pubkey/'
)
4 years ago
if name: nm=self.crypt_keys.get(
4 years ago
b64enc(pubkey),
prefix='/name/'
)
4 years ago
self.log(f'checking whether I have user {name} and {pubkey},\n I discovered I had {nm} and {pk} on record')
4 years ago
# self.log('pks:',pubkey,pk)
# self.log('nms:',name,nm)
4 years ago
return (pubkey and pk) or (name and nm)
4 years ago
def send(self,encr_data_b):
self.log(type(encr_data_b),encr_data_b,'sending!')
return encr_data_b
### ROUTES
4 years ago
def does_username_exist(self,msg_obj):
data=msg_obj.data
name=data.get('name')
pubkey=self.crypt_keys.get(name,prefix='/pubkey/')
self.log(f'looking for {name}, found {pubkey} as pubkey')
return bool(pubkey)
def login(self,msg_obj):
data=msg_obj.data
name=data.get('name')
pubkey=data.get('pubkey')
secret_login=data.get('secret_login')
4 years ago
name=name.encode() if type(name)==str else name
4 years ago
uri = b64enc(pubkey)
secret_login = b64enc(secret_login)
4 years ago
name_record = self.crypt_keys.get(
4 years ago
uri,
4 years ago
prefix='/name/'
4 years ago
)
4 years ago
print(uri,name,name_record,'??')
4 years ago
pubkey_record = b64enc(self.crypt_keys.get(
4 years ago
name,
prefix='/pubkey/'
4 years ago
))
secret_record = b64enc(self.crypt_keys.get(
4 years ago
uri,
4 years ago
prefix='/secret_login/'
4 years ago
))
4 years ago
self.log(f'''Checking inputs:
4 years ago
{name} (input)
vs.
{name_record} (record)
{uri} (input)
vs.
{pubkey_record} (record)
{secret_login} (input)
vs.
{secret_record} (record)
''')
4 years ago
# stop
# check name?
4 years ago
if name != name_record:
4 years ago
self.log('names did not match!')
success = False
4 years ago
# # check pubkey?
4 years ago
elif uri != pubkey_record:
self.log('pubkeys did not match!',uri,pubkey_record)
success = False
elif secret_login != secret_record:
self.log('secrets did not match!')
success = False
else:
success = True
## return res
if success:
return {
'success': True,
'status':f'Welcome back, Comrad @{name.decode()}.',
4 years ago
'status_type':'login',
4 years ago
'name':name_record.decode(),
4 years ago
'pubkey':pubkey_record
4 years ago
}
else:
return {
'success': False,
4 years ago
'status':'Login failed.',
4 years ago
'status_type':'login',
4 years ago
}
4 years ago
def register_new_user(self,msg_obj):
4 years ago
# self.log('setting pubkey under name')
data=msg_obj.data
name=data.get('name')
pubkey=data.get('pubkey')
4 years ago
# is user already there?
if self.has_user(name=name,pubkey=pubkey):
return {
'success':False,
'status': f"{OPERATOR_INTRO}I'm sorry, but I can't register the name of {name}. This comrad already exists."
4 years ago
}
4 years ago
4 years ago
# generate shared secret
4 years ago
shared_secret = get_random_binary_id()
4 years ago
self.log(f'{self}: Generated shared secret between {name} and me:\n\n{make_key_discreet(shared_secret)}')
4 years ago
# ok then set what we need
4 years ago
uri_id = b64enc(pubkey)
4 years ago
pubkey_b = b64dec(pubkey)
4 years ago
r1=self.crypt_keys.set(name,pubkey_b,prefix='/pubkey/')
r2=self.crypt_keys.set(uri_id,name,prefix='/name/')
4 years ago
# hide secret as key
4 years ago
r3=self.crypt_keys.set(uri_id,shared_secret,prefix='/secret_login/')
4 years ago
# success?
success = r1 and r2 and r3
if not success:
return {
'success':False,
'status': f"{OPERATOR_INTRO}I'm sorry, but I can't register the name of {name}."
}
4 years ago
4 years ago
# save QR also?
self.save_uri_as_qrcode(uri_id=uri_id,name=name)
4 years ago
# compose result
4 years ago
res = {
'success':success,
4 years ago
'pubkey':pubkey_b,
4 years ago
'secret_login':shared_secret,
4 years ago
'name':name,
4 years ago
'status':f'Comrad @{name} was successfully registered. That name has been permanently linked to this public key:\n{uri_id.decode()}',
4 years ago
'res_posts':self.get_posts(msg_obj)
4 years ago
}
4 years ago
# res_safe = {
# **res,
# **{
# 'secret_login':make_key_discreet(
# res['secret_login']
# )
# }
# }
4 years ago
# return
4 years ago
self.log('Operator returning result:',dict_format(res,tab=4))
4 years ago
return res
4 years ago
4 years ago
4 years ago
## success msg
4 years ago
#
4 years ago
# cvb64=cv_b64#b64encode(cv).decode()
# qrstr=self.qr_str(cvb64)
# res['status']=self.status(f'''{OPERATOR_INTRO}I have successfully registered Comrad {name}.
4 years ago
4 years ago
# If you're interested, here's what I did. I stored the public key you gave me, {cvb64}, under the name of "{name}". However, I never save that name directly, but record it only in a disguised, "hashed" form: {ck}. I scrambled "{name}" by running it through a 1-way hashing function, which will always yield the same result: provided you know which function I'm using, and what the secret "salt" is that I add to all the input, a string of text which I keep protected and encrypted on my local hard drive.
4 years ago
4 years ago
# The content of your data will therefore not only be encrypted, but its location in my database is obscured even to me. There's no way for me to reverse-engineer the name of {name} from the record I stored it under, {ck}. Unless you explictly ask me for the public key of {name}, I will have no way of accessing that information.
4 years ago
# Your name ({name}) and your public key ({cvb64}) are the first two pieces of information you've given me about yourself. Your public key is your 'address' in Comrad: in order for anyone to write to you, or for them to receive messages from you, they'll need to know your public key (and vise versa). The Comrad app should store your public key on your device as a QR code, under ~/.comrad/.contacts/{name}.png. It will look something like this:{qrstr}You can then send this image to anyone by a secure channel (Signal, IRL, etc), or tell them the code directly ({cvb64}).
4 years ago
4 years ago
# By default, if anyone asks me what your public key is, I won't tell them--though I won't be able to avoid hinting that a user exists under this name should someone try to register under that name and I deny them). Instead, if the person who requested your public key insists, I will send you a message (encrypted end-to-end so only you can read it) that the user who met someone would like to introduce themselves to you; I will then send you their name and public key. It's now your move: up to you whether to save them back your public key.
4 years ago
4 years ago
# If you'd like to change this default behavior, e.g. by instead allowing anyone to request your public key, except for those whom you explcitly block, I have also created a super secret administrative record for you to change various settings on your account. This is protected by a separate encryption key which I have generated for you; and this key which is itself encrypted with the password you entered earlier. Don't worry: I never saw that password you typed, since it was given to me already hashed and disguised. Without that hashed passphrase, no one will be able to unlock the administration key; and without the administration key, they won't be able to find the hashed record I stored your user settings under, since I also salted that hash with your own hashed passphrase. Even if someone found the record I stored them under, they wouldn't be able to decrypt the existing settings; and if they can't do that, I won't let them overwrite the record.''')
4 years ago
4 years ago
# self.log('Operator returning result:',dict_format(res,tab=2))
4 years ago
4 years ago
def validate_msg(self,msg_d):
from comrad.backend.messages import is_valid_msg_d
4 years ago
if not is_valid_msg_d(msg_d): return False
# alleged
(
alleged_to_name,
alleged_to_pub,
alleged_from_name,
alleged_from_pub
) = (
msg_d.get('to_name'),
msg_d.get('to'),
msg_d.get('from_name'),
msg_d.get('from')
)
# recorded
(
real_to_name,
real_to_pub,
real_from_name,
real_from_pub
) = (
self.find_name(alleged_to_pub),
4 years ago
self.find_pubkey(alleged_to_name).data_b64,
4 years ago
self.find_name(alleged_from_pub),
4 years ago
self.find_pubkey(alleged_from_name).data_b64
4 years ago
)
4 years ago
4 years ago
self.log(f'''
alleged_to_name = {alleged_to_name}
alleged_to_pub = {alleged_to_pub}
alleged_from_name = {alleged_from_name}
alleged_from_pub = {alleged_from_pub}
real_to_name = {real_to_name}
real_to_pub = {real_to_pub}
real_from_name = {real_from_name}
real_from_pub = {real_from_pub}
''')
4 years ago
try:
assert alleged_to_name == real_to_name
assert alleged_to_pub == real_to_pub
assert alleged_from_name == real_from_name
assert alleged_from_pub == real_from_pub
except AssertionError:
return False
return True
4 years ago
4 years ago
def deliver_msg(self,msg_to_op):
4 years ago
self.log('<-',msg_to_op)
data = msg_to_op.data
4 years ago
self.log('<- data',msg_to_op.data)
4 years ago
deliver_msg_d = data.get('deliver_msg')
4 years ago
self.log('<- deliver_msg_d',deliver_msg_d)
return self.deliver_msg_d(deliver_msg_d)
def deliver_msg_d(self,deliver_msg_d):
self.log('<- deliver_msg_d',deliver_msg_d)
4 years ago
4 years ago
# is valid?
if not self.validate_msg(deliver_msg_d):
4 years ago
res = {
'status':'Message was not valid. Records between Comrad and Operator do not match.',
4 years ago
'success':False
}
4 years ago
self.log('-->',res)
4 years ago
4 years ago
# encode
deliver_msg_b = pickle.dumps(deliver_msg_d)
self.log('<-- deliver_msg_b',deliver_msg_b)
4 years ago
4 years ago
# encrypt
4 years ago
deliver_to = b64enc(deliver_msg_d['to'])
4 years ago
deliver_to_b = b64dec(deliver_to)
4 years ago
deliver_msg_b_encr = SMessage(
self.privkey.data,
deliver_to_b
).wrap(deliver_msg_b)
self.log('<-- deliver_msg_b_encr',deliver_msg_b_encr)
4 years ago
4 years ago
# actually deliver
4 years ago
post_id = get_random_binary_id()
4 years ago
self.crypt_data.set(
4 years ago
post_id,
4 years ago
deliver_msg_b_encr,
4 years ago
prefix='/post/'
)
4 years ago
self.log(f'put {deliver_msg_b_encr} in {post_id}')
4 years ago
4 years ago
# get inbox
4 years ago
inbox_crypt = self.get_inbox_crypt(
4 years ago
uri=deliver_to
4 years ago
)
4 years ago
self.log('inbox_crypt',inbox_crypt)
self.log('inbox_crypt.values',inbox_crypt.values)
res_inbox = inbox_crypt.prepend(post_id)
4 years ago
self.log('inbox_crypt.values v2',inbox_crypt.values)
4 years ago
res = {
4 years ago
'status':'Message delivered.',
'success':True,
4 years ago
'post_id':post_id,
4 years ago
'res_inbox':res_inbox,
'msg_d':deliver_msg_d
4 years ago
}
4 years ago
self.log('->',res)
4 years ago
return res
4 years ago
4 years ago
def deliver_post(self,msg_to_op):
4 years ago
# This
self.log('<--',msg_to_op.msg_d)
world = Comrad(WORLD_NAME)
4 years ago
# attached msg
4 years ago
attached_msg = msg_to_op.msg.get('data')
4 years ago
self.log('attached_msg =',attached_msg)
4 years ago
if not attached_msg: return
4 years ago
# double encrypt it as a message to world
attached_msg_encr_op2world = SMessage(
self.privkey.data,
world.pubkey.data
).wrap(attached_msg)
4 years ago
# just store as the encrypted binary -> world it came in?
# save
4 years ago
post_id = get_random_binary_id()
self.crypt_data.set(
post_id,
4 years ago
attached_msg_encr_op2world,
4 years ago
prefix='/post/'
)
4 years ago
self.log(f'put {attached_msg_encr_op2world} in {post_id}')
4 years ago
# update post index
post_index = self.get_inbox_crypt(
4 years ago
uri='posts',
4 years ago
prefix='/index/'
)
self.log('post_index',post_index)
post_index.prepend(post_id)
res = {
'status':'Saved message successfully',
'success':True,
'post_id':post_id,
4 years ago
'msg_saved':attached_msg,
# last minute post grab?
'res_posts':self.get_posts(msg_to_op)
4 years ago
}
self.log('res =',res)
return res
def get_posts(self,msg_to_op,max_posts=25):
# data
self.log('<-',msg_to_op)
data=msg_to_op.data
self.log('<- data',data)
seen = set(data.get('seen',[]))
self.log('seen =',seen)
# get index
world=Comrad(WORLD_NAME)
4 years ago
self.log('world name??',WORLD_NAME,'??????')
4 years ago
index = self.get_inbox_crypt(
4 years ago
uri='posts',
4 years ago
prefix='/index/'
)
self.log('<- index',index)
post_ids = [x for x in index.values if not x in seen]
self.log('post_ids =',post_ids)
# get posts
4 years ago
# self.log('world keys are:',world.keychain().keys())
4 years ago
4 years ago
id2post={}
4 years ago
for post_id in post_ids:
4 years ago
# skip if seen?
if self.crypt_data.get(
msg_to_op.from_pubkey,
prefix=b'/seen/' + post_id + b'/'
):
self.log('skipping: comrad has already seen!')
4 years ago
continue
4 years ago
encr_msg_content_op2world = self.crypt_data.get(
4 years ago
post_id,
prefix='/post/'
)
4 years ago
self.log('<-- encr_msg_content_op2world',encr_msg_content_op2world,'at post id',post_id)
if not encr_msg_content_op2world: continue
# decrypt from op
post_pkg_b = SMessage(
world.privkey.data,
self.pubkey.data
).unwrap(encr_msg_content_op2world)
self.log('post_pkg_b',post_pkg_b)
# decode
post_pkg_d = pickle.loads(post_pkg_b)
self.log('post_pkg_d',post_pkg_d)
from_uri = post_pkg_d.get('post_from')
from_name = post_pkg_d.get('post_from_name')
4 years ago
post_timestamp = post_pkg_d.get('post_timestamp')
4 years ago
post_b_signed_encr4world = post_pkg_d.get('post')
4 years ago
# if not from_uri or not from_name or b64enc(self.find_pubkey(from_name))!=from_uri or not post_b_signed_encr4world:
# return {
# 'success':False,
# 'status':'Records do not match.'
# }
# decrypt from post author comrad
4 years ago
post_b_signed = SMessage(
world.privkey.data,
b64dec(from_uri)
).unwrap(post_b_signed_encr4world)
self.log('post_b_signed',post_b_signed)
# re-encrypt for the post requester comrad
4 years ago
post_pkg_d2 = {
'post':post_b_signed,
'post_from':from_uri,
4 years ago
'post_from_name':from_name,
'post_timestamp':post_timestamp
4 years ago
}
post_pkg_b2 = pickle.dumps(post_pkg_d2)
post_pkg_b2_encr_op2kom = SMessage(
self.privkey.data,
b64dec(msg_to_op.from_pubkey)
).wrap(post_pkg_b2)
# store and return this
id2post[post_id] = post_pkg_b2_encr_op2kom
4 years ago
# store whether this user has seen this post?
self.crypt_data.set(
msg_to_op.from_pubkey,
'y',
prefix=b'/seen/' + post_id + b'/'
)
4 years ago
res = {
'status':f'Succeeded in getting {len(id2post)} new posts.',
'success':True,
'posts':id2post
}
self.log('-->',res)
return res
4 years ago
# def deliver_msg(self,msg_to_op):
# data = msg_to_op.data
# deliver_msg_d = data.get('deliver_msg')
# # is valid?
# if not self.validate_msg(deliver_msg_d):
# res = {
# 'status':'Message was not valid. Records between Comrad and Operator do not match.',
4 years ago
# 'success':False
# }
# self.log('-->',res)
# # package
# from comrad.backend.messages import Message
4 years ago
# msg_from_op = Message(
# from_whom=self,
# msg_d = {
# 'to':deliver_msg_d.get('to'),
# 'to_name':deliver_msg_d.get('to_name'),
# 'msg':deliver_msg_d
# }
# )
# self.log(f'{self}: Prepared this msg for delivery:\n{msg_from_op}\n\n{dict_format(msg_from_op.msg_d)}')
# # encrypt
# msg_from_op.encrypt()
# self.log("Here's what it looks like before I actually_deliver it",dict_format(msg_from_op.msg_d))
# # deliver
# return self.actually_deliver_msg(msg_from_op)
# def actually_deliver_msg(self,msg_from_op):
# self.log('msg_from_op <-',msg_from_op)
# self.log('msg_from_op.msg_d <-',msg_from_op.msg_d)
# self.log('msg_from_op.msg_b <-',msg_from_op.msg_b)
# self.log('msg_from_op.msg <-',msg_from_op.msg)
# msg_from_op_b_encr = msg_from_op.msg #.msg_b # pickle of msg_d
# self.log('msg_from_op_b_encr <-',msg_from_op_b_encr)
# deliver_to = b64enc(msg_from_op.to_pubkey)
# deliver_to_b = b64dec(deliver_to)
# # save new post
# post_id = get_random_binary_id()
# self.crypt_data.set(
# post_id,
# msg_from_op_b_encr,
# prefix='/post/'
# )
# self.log(f'put {msg_from_op} (or {msg_from_op_b_encr}) in {post_id}')
# # get inbox
# inbox_crypt = self.get_inbox_crypt(
# uri=deliver_to
# )
# self.log('inbox_crypt',inbox_crypt)
# self.log('inbox_crypt.values',inbox_crypt.values)
# res_inbox = inbox_crypt.prepend(post_id)
# self.log('inbox_crypt.values v2',inbox_crypt.values)
# res = {
# 'status':'Message delivered.',
# 'success':True,
# 'post_id':post_id,
# 'res_inbox':res_inbox
# }
# self.log('->',res)
# return res
###
# LETS SIMPLIFY THIS
# Comrad -> Op: get_updates()
# gets new DMs, new posts,
# both index/inbox and content/body
###
def require_login(self,msg_to_op,do_login=True):
4 years ago
# logged in?
4 years ago
if do_login:
login_res = self.login(msg_to_op)
4 years ago
return login_res
else:
4 years ago
return {
'success':True,
'status':'Login not required.',
'name':msg_to_op.from_name,
'pubkey':msg_to_op.from_pubkey
}
# (0) get updates
# user enters here
def get_updates(self,
msg_to_op=None,
inbox_uri=None,
do_login=True,
4 years ago
include_posts=True):
self.log('<-',msg_to_op,inbox_uri)
# uri?
if not inbox_uri and not msg_to_op:
return {'success':False, 'status':'Updates for whom?'}
4 years ago
uri = inbox_uri if inbox_uri else b64enc(msg_to_op.from_pubkey)
4 years ago
# (1) req login?
res_login={}
if do_login:
if not msg_to_op:
4 years ago
return {'success':False,'status':'Cannot login outside of message context.'}
res_login=self.require_login(msg_to_op,do_login=do_login)
4 years ago
if not res_login.get('success'):
4 years ago
return {'success':False,'res_login':res_login}
# (2) get msgs
4 years ago
res_msgs = self.get_msgs(uri)
self.log('res_msgs',res_msgs)
4 years ago
msgs=res_msgs.get('posts',{})
# (3) get posts
4 years ago
res_posts={}
4 years ago
if include_posts:
4 years ago
res_posts = self.get_posts(msg_to_op)
4 years ago
self.log('res_posts',res_posts)
4 years ago
posts=res_posts.get('posts',{})
4 years ago
# return
res={
'success': True,
'status': f'You have {len(msgs)} new messages, and {len(posts)} new posts.',
4 years ago
'res_login':res_login,
'res_msgs':res_msgs,
'res_posts':res_posts,
}
self.log('-->',res)
return res
# (1) get inbox
def get_inbox(self,inbox_uri):
4 years ago
# ok, then find the inbox?
4 years ago
self.log('get_inbox <-',inbox_uri)
4 years ago
inbox=self.get_inbox_crypt(
4 years ago
uri=b64enc(inbox_uri),
4 years ago
)
4 years ago
self.log('<-inbox <-',inbox)
4 years ago
4 years ago
res = {
4 years ago
'status':'Succeeded in getting inbox.',
'success':True,
'inbox':inbox.values if inbox else []
4 years ago
}
self.log(f'--> {res}')
4 years ago
return res
4 years ago
def get_msgs(self,inbox_uri,delete_afterward=True):
4 years ago
# (1) get inbox
inbox_obj=self.get_inbox_crypt(uri=inbox_uri)
self.log('<-- inbox crypt',inbox_obj)
inbox=inbox_obj.values
self.log('<-- inbox crypt values',inbox)
# (2) get msgs
id2msg={}
for post_id in inbox:
post = self.crypt_data.get(
post_id,
prefix='/post/'
)
4 years ago
if post:
id2msg[post_id] = post
self.log(f'I {self} found {len(id2msg)}')
4 years ago
# delete?
if delete_afterward:
del_res = self.delete_posts(
post_ids = list(id2msg.keys())
)
self.log('del_res',del_res)
else:
del_res={}
4 years ago
res = {
4 years ago
'status':f'Succeeded in getting {len(id2msg)} new messages.',
4 years ago
'success':True,
4 years ago
'posts':id2msg,
'res_delete':del_res
4 years ago
}
self.log(f'--> {res}')
4 years ago
return res
4 years ago
4 years ago
###
# INTRODUCTIONS/MEETING
###
4 years ago
def introduce(self,msg_to_op):
4 years ago
# # logged in?
# self.log('introduce got:',msg_to_op)
# login_res = self.login(msg_to_op)
# self.log('introduce got login-res:',login_res)
# if not login_res.get('success'):
# return login_res
4 years ago
4 years ago
data=msg_to_op.data
4 years ago
self.log('Op sees data:',dict_format(data))
4 years ago
meet_pubkey = self.crypt_keys.get(
data.get('meet_name'),
'/pubkey/'
)
4 years ago
if not meet_pubkey:
return {
'success':False,
'status':'Are you sure this comrad exists? If you are, try contacting them by another secure channel and asking for their public key there.'
4 years ago
}
4 years ago
self.log('found in crypt:',meet_pubkey)
4 years ago
meet_name = data.get('meet_name')
4 years ago
meet_uri = b64enc(meet_pubkey)
4 years ago
meet_from_name = data.get('name')
meet_from_uri = data.get('pubkey')
4 years ago
returning = data.get('returning')
4 years ago
other_data = data.get('other_data')
4 years ago
if returning:
4 years ago
# txt=f'''Comrad @{meet_from_name} has agreed to make your acquaintance.\n\nTheir public key is:\n{meet_from_uri.decode()}.'''
txt=f'''Comrad @{meet_from_name} has agreed to make your acquaintance.'''
4 years ago
else:
4 years ago
# txt=f'''Comrad @{meet_from_name} would like to make your acquaintance.\n\nTheir public key is:\n{meet_from_uri.decode()}.'''
txt=f'''Comrad @{meet_from_name} would like to make your acquaintance.'''
4 years ago
4 years ago
# txt_encr = SMessage(
# self.privkey.data,
# b64dec(meet_uri)
# ).wrap(txt)
# self.log('txt -> encr',txt,txt_encr)
4 years ago
4 years ago
deliver_msg_d={
4 years ago
'to':meet_uri,
'to_name':meet_name,
4 years ago
4 years ago
'from':self.uri,
'from_name':self.name,
4 years ago
4 years ago
'msg':{
'txt':txt,
'type':'prompt',
4 years ago
'prompt_id':'addcontact',
'meet_name':meet_from_name,
4 years ago
'meet':meet_from_uri,
4 years ago
'returning':returning,
'other_data':other_data
4 years ago
}
4 years ago
}
self.log('deliver_msg_d ->',deliver_msg_d)
return self.deliver_msg_d(deliver_msg_d)
4 years ago
4 years ago
4 years ago
def test_op():
from comrad.backend.the_telephone import TheTelephone
4 years ago
4 years ago
from getpass import getpass
4 years ago
op = TheOperator()
4 years ago
# op.boot()
4 years ago
keychain_op = op.keychain()
4 years ago
4 years ago
4 years ago
phone = TheTelephone()
# phone.boot()
4 years ago
keychain_ph = phone.keychain()
4 years ago
world = Comrad(WORLD_NAME)
4 years ago
keychain_w = world.keychain()
4 years ago
4 years ago
from pprint import pprint
4 years ago
print('REASSEMBLED OPERATOR KEYCHAIN')
4 years ago
print(dict_format(keychain_op))
4 years ago
# stop
4 years ago
print()
4 years ago
4 years ago
print('REASSEMBLED TELEPHONE KEYCHAIN')
4 years ago
print(dict_format(keychain_ph))
print()
print('REASSEMBLED WORLD KEYCHAIN')
print(dict_format(keychain_w))
print()
4 years ago
4 years ago
# print(op.pubkey(keychain=keychain))
4 years ago
# print(op.crypt_keys.get(op.pubkey(), prefix='/privkey_encr/'))
4 years ago
# print(op.crypt_keys.get(op.name, prefix='/pubkey_encr/'))
4 years ago
# print(op.pubkey_)
4 years ago
4 years ago
4 years ago
# stop
4 years ago
4 years ago
# pubkey = op.keychain()['pubkey']
# pubkey_b64 = b64encode(pubkey)
# print(pubkey)
4 years ago
if __name__ == '__main__': test_op()