diff --git a/komrade/api/api.py b/komrade/api/api.py
index 6a22c69..435aaf0 100644
--- a/komrade/api/api.py
+++ b/komrade/api/api.py
@@ -374,8 +374,8 @@ class Api(object):
timestamp = b64decode(time_b64).decode()
tmpP = Persona(from_name)
await tmpP.boot()
- from_pubkey_b64_acc_to_name = tmpP.pubkey_b64
- assert from_pubkey_b64==from_pubkey_b64_acc_to_name
+ from_pubkey_b64_accto_name = tmpP.pubkey_b64
+ assert from_pubkey_b64==from_pubkey_b64_accto_name
encrypted_payload_b64 = self.verify(signed_encrypted_payload_b64, from_pubkey_b64)
self.log('encrypted_payload_b64 =',encrypted_payload_b64)
diff --git a/komrade/api/persona0.py b/komrade/api/persona0.py
index 5e6674d..e8a6b70 100644
--- a/komrade/api/persona0.py
+++ b/komrade/api/persona0.py
@@ -659,8 +659,8 @@ class Persona(object):
timestamp = b64decode(time_b64).decode()
tmpP = Persona(from_name)
await tmpP.boot()
- from_pubkey_b64_acc_to_name = tmpP.pubkey_b64
- assert from_pubkey_b64==from_pubkey_b64_acc_to_name
+ from_pubkey_b64_accto_name = tmpP.pubkey_b64
+ assert from_pubkey_b64==from_pubkey_b64_accto_name
encrypted_payload_b64 = self.verify(signed_encrypted_payload_b64, from_pubkey_b64)
self.log('encrypted_payload_b64 =',encrypted_payload_b64)
diff --git a/komrade/app/main.py b/komrade/app/main.py
index 25595ea..09fec75 100644
--- a/komrade/app/main.py
+++ b/komrade/app/main.py
@@ -2,7 +2,8 @@
# change this to your external ip address for your server
#(needs to be external to allow tor routing)
from config import *
-
+import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
+from komrade import *
@@ -53,9 +54,6 @@ from kivy.uix.image import Image
import sys
sys.path.append("..") # Adds higher directory to python modules path.
-from p2p.api import *
-from p2p.persona import *
-
from kivy.event import EventDispatcher
import threading,asyncio,sys
diff --git a/komrade/backend/keymaker.py b/komrade/backend/keymaker.py
index afa8429..fd6767f 100644
--- a/komrade/backend/keymaker.py
+++ b/komrade/backend/keymaker.py
@@ -569,12 +569,12 @@ Keymaker ({self}) is forging new keys for {name}
encr_key = keychain.get(encr_key_name)
# self.log(f'about to decrypt {encr_key} with {decr_key}')
unencr_key = decr_key.decrypt(encr_key.data)
- keychain[unencr_key_name] = get_key_obj(unencr_key_name,unencr_key.data)
+ keychain[unencr_key_name] = get_key_obj(unencr_key_name,unencr_key)
else:
unencr_key = keychain.get(unencr_key_name)
# self.log(f'about to encrypt {unencr_key} with {decr_key}')
encr_key = decr_key.encrypt(unencr_key.data)
- keychain[encr_key_name] = get_key_obj(encr_key_name,encr_key.data)
+ keychain[encr_key_name] = get_key_obj(encr_key_name,encr_key)
except ThemisError:
pass
diff --git a/komrade/backend/messages.py b/komrade/backend/messages.py
index 5c70098..ad57520 100644
--- a/komrade/backend/messages.py
+++ b/komrade/backend/messages.py
@@ -4,12 +4,13 @@ from komrade.backend import *
def is_valid_msg_d(msg_d):
if not type(msg_d)==dict: return False
- to_name=msg_d.get('_to_name')
- to_pub=msg_d.get('_to_pub')
- from_name=msg_d.get('_from_name')
- from_pub=msg_d.get('_from_pub')
- msg=msg_d.get('_msg')
- if to_name and to_pub and from_name and from_pub and msg: return True
+ to_name=msg_d.get('to_name')
+ to_pub=msg_d.get('to')
+ from_name=msg_d.get('from_name')
+ from_pub=msg_d.get('from')
+ msg=msg_d.get('msg')
+ # if to_name and to_pub and from_name and from_pub and msg: return True
+ if to_pub and from_pub and msg: return True
return False
@@ -20,11 +21,11 @@ class Message(Logger):
raise KomradeException('This is not a valid msg_d:',msg_d)
# set fields
self.msg_d=msg_d
- self.to_name=msg_d.get('_to_name')
- self.to_pubkey=msg_d.get('_to_pub')
- self.from_name=msg_d.get('_from_name')
- self.from_pubkey=msg_d.get('_from_pub')
- self.msg=msg_d.get('_msg')
+ self.to_name=msg_d.get('to_name')
+ self.to_pubkey=msg_d.get('to')
+ self.from_name=msg_d.get('from_name')
+ self.from_pubkey=msg_d.get('from')
+ self.msg=msg_d.get('msg')
self.embedded_msg=embedded_msg # only if this message has an embedded one
self._route=msg_d.get(ROUTE_KEYNAME)
self._from_whom=from_whom
@@ -37,13 +38,15 @@ class Message(Logger):
def __repr__(self):
msg_d_str=dict_format(self.msg_d,tab=6)
+ if type(self.msg)==dict:
+ msg=dict_format(self.msg,tab=4)
+ else:
+ msg=self.msg
return f"""
-
- self.from_whom={self.from_whom}
- self.to_whom={self.to_whom}
- self.msg={dict_format(self.msg,tab=4) if type(self.msg)==dict else self.msg}
-
- """
+ from: {self.from_whom}
+ to: {self.to_whom}
+ msg: {msg}
+"""
@property
@@ -52,21 +55,20 @@ class Message(Logger):
msg_d=self.msg_d
while msg_d:
for k,v in msg_d.items(): md[k]=v
- msg_d = msg_d.get('_msg',{})
+ msg_d = msg_d.get('msg',{})
if type(msg_d)!=dict: msg_d=None
- if '_msg' in md and type(md['_msg']) == dict:
- del md['_msg']
+ if 'msg' in md and type(md['msg']) == dict:
+ del md['msg']
del md[ROUTE_KEYNAME]
return md
def mark_return_to_sender(self,new_msg=None):
self._from_whom,self._to_whom = self._to_whom,self._from_whom
- self.msg_d['_from_pub'],self.msg_d['_to_pub'] = self.msg_d['_to_pub'],self.msg_d['_from_pub'],
- self.msg_d['_from_name'],self.msg_d['_to_name'] = self.msg_d['_to_name'],self.msg_d['_from_name'],
+ self.msg_d['from'],self.msg_d['to'] = self.msg_d['to'],self.msg_d['from'],
+ self.msg_d['from_name'],self.msg_d['to_name'] = self.msg_d['to_name'],self.msg_d['from_name'],
if new_msg:
- self.msg=self.msg_d['_msg']=new_msg
+ self.msg=self.msg_d['msg']=new_msg
-
def get_whom(self,name):
from komrade.backend.operators import locate_an_operator
return locate_an_operator(name)
@@ -126,14 +128,14 @@ class Message(Logger):
self.log(f'attempting to decrypt {self}')
# decrypt msg
- self.msg = self.msg_d['_msg'] = decr_msg_b = SMessage(
+ self.msg = self.msg_d['msg'] = decr_msg_b = SMessage(
self.to_whom.privkey,
self.from_whom.pubkey
).unwrap(self.msg)
# self.log('Am I decrypted?',self)
# unpickle
- self.msg = self.msg_d['_msg'] = decr_msg = pickle.loads(decr_msg_b)
+ self.msg = self.msg_d['msg'] = decr_msg = pickle.loads(decr_msg_b)
self.log('I am now decrypted and unpickled:',self)
# now, is the decrypted message itself a message?
@@ -159,7 +161,7 @@ class Message(Logger):
def encrypt(self): # each child message should already be encrypted before coming to its parent message ,recursive=False):
if self._is_encrypted: return
# self.log(f'attempting to encrypt msg {self.msg} from {self.from_whom} to {self.to_whom}')
- self.log(f'About to encrypt self.msg! I now look like v1: {self}')
+ self.log(f'I ({self.from_whom}) am about to encrypt my message to {self.to_whom},\n "end to end" so that only {self.to_whom} can read it.\n\n Before encryption, I look like:\n{self}')
# make sure msg is not meeta
if self.has_embedded_msg:
@@ -177,9 +179,9 @@ class Message(Logger):
).wrap(msg_b)
self.msg_decr = self.msg
- self.msg = msg_encr
- self.msg_d['_msg'] = msg_encr
- self.log(f'Encrypted! I now look like v2: {self}')
+ self.msg_d['msg'] = self.msg = b64encode(msg_encr)
+ self.log(f'I ({self.from_whom}) am about to encrypt my message to {self.to_whom}\n "end to end" so that only {self.to_whom} can read it.\n\n And after encryption, I look like:\n{self}')
+ self.msg_d['msg'] = self.msg = msg_encr
self._is_encrypted = True
@@ -216,8 +218,8 @@ class Message(Logger):
def delete_route(self):
if type(self.msg)==dict:
del self.msg[ROUTE_KEYNAME]
- if ROUTE_KEYNAME in self.msg_d['_msg']:
- del self.msg_d['_msg'][ROUTE_KEYNAME]
+ if ROUTE_KEYNAME in self.msg_d['msg']:
+ del self.msg_d['msg'][ROUTE_KEYNAME]
if self.has_embedded_msg:
self.msg.delete_route()
diff --git a/komrade/backend/operators.py b/komrade/backend/operators.py
index bf35960..0aa035f 100644
--- a/komrade/backend/operators.py
+++ b/komrade/backend/operators.py
@@ -33,7 +33,7 @@ class Operator(Keymaker):
from komrade.backend.phonelines import check_phonelines
check_phonelines()
- print(self.crypt_keys.get(OPERATOR_NAME,prefix='/pubkey/'))
+ # print(self.crypt_keys.get(OPERATOR_NAME,prefix='/pubkey/'))
# stop
@@ -75,7 +75,7 @@ class Operator(Keymaker):
return OPERATOR
- def compose_msg_to(self,msg,another,route=None):
+ def compose_msg_to(self,msg,another,incl_from_name=False,incl_to_name=False):
if not self.privkey or not self.pubkey:
raise KomradeException('why do I have no pub/privkey pair!?',self,self.name,self.pubkey,self.privkey,self.keychain())
if not another.name or not another.pubkey:
@@ -83,13 +83,14 @@ class Operator(Keymaker):
# otherwise create msg
msg_d = {
- '_from_pub':self.pubkey,
- '_from_name':self.name,
- '_to_pub':another.pubkey,
- '_to_name':another.name,
- '_msg':msg,
- ROUTE_KEYNAME:route
+ 'from':self.pubkey.data,
+ # 'from_name':self.name,
+ 'to':another.pubkey.data,
+ # 'to_name':another.name,
+ 'msg':msg
}
+ if incl_from_name: msg_d['from_name']=self.name
+ if incl_to_name: msg_d['to_name']=self.name
# self.log(f'I am {self} packaging a message to {another}: {msg_d}')
from komrade.backend.messages import Message
@@ -104,24 +105,16 @@ class Operator(Keymaker):
def seal_msg(self,msg_d):
- # make sure encrypted
- self.log('sealing msg!:',dict_format(msg_d))
- # msg_obj.encrypt(recursive=True)
- # return pure binary version of self's entire msg_d
msg_b = pickle.dumps(msg_d)
- self.log('pickled!',msg_b)
-
- # encrypt by omega key
- msg_b_encr = self.omega_key.encrypt(msg_b)
- self.log('final seal:',msg_b_encr)
-
+ self.log('Message has being sealed in a final binary package:',b64encode(msg_b))
return msg_b_encr
def unseal_msg(self,msg_b_encr,from_whom=None,to_whom=None):
# default to assumption that I am the recipient
if not to_whom: to_whom=self
# decrypt by omega
- msg_b = self.omega_key.decrypt(msg_b_encr)
+ # msg_b = self.omega_key.decrypt(msg_b_encr)
+ msg_b = msg_b_encr
# unpackage from transmission
msg_d = pickle.loads(msg_b)
# get message obj
@@ -134,19 +127,21 @@ class Operator(Keymaker):
def __repr__(self):
clsname=(type(self)).__name__
- name = clsname+' '+self.name if self.name!=clsname else clsname
- try:
- keystr='+'.join(self.top_keys) if self.pubkey else ''
- except TypeError:
- keystr=''
- # if self.pubkey:
+ #name = clsname+' '+
+ name = 'Komrade @'+self.name # if self.name!=clsname else clsname
+ # try:
+ # keystr= 'on device: ' + ('+'.join(self.top_keys) if self.pubkey else '')
+ # except TypeError:
+ # keystr=''
+ # # if self.pubkey:
+ keystr=''
if False:
pubk=self.pubkey_b64.decode()
pubk=pubk[-5:]
pubk = f' ({pubk})'# if pubk else ''
else:
pubk = ''
- return f'[{name}]{pubk} ({keystr})'
+ return f'{name}' #' ({keystr})'
def locate_an_operator(self,name):
if name == OPERATOR_NAME:
@@ -171,12 +166,12 @@ class Operator(Keymaker):
# route it!
func = getattr(self,route)
new_data = func(**data)
- msg_obj.msg = msg_obj.msg_d['_msg'] = new_data
+ msg_obj.msg = msg_obj.msg_d['msg'] = new_data
# try passing it on?
if msg_obj.has_embedded_msg:
new_data = self.route_msg(msg_obj.msg)
- msg_obj.msg = msg_obj.msg_d['_msg'] = new_data
+ msg_obj.msg = msg_obj.msg_d['msg'] = new_data
# time to turn around and encrypt
msg_obj.mark_return_to_sender()
@@ -189,36 +184,46 @@ class Operator(Keymaker):
return msg_obj
- def ring_ring(self,msg,to_whom,from_whom=None,get_resp_from=None,route=None):
+ def ring_ring(self,msg,to_whom,get_resp_from=None,route=None,caller=None):
# ring ring
from komrade.cli.artcode import ART_PHONE_SM1
import textwrap as tw
- self.log(f'''
-
-{ART_PHONE_SM1}
-ring ring ring!
-
-I am {self}. I have been given a message by {from_whom}, and told to pass it onto {to_whom}, by way of the function {get_resp_from}.
+ nxt=get_class_that_defined_method(get_resp_from).__name__
+ nxtfunc=get_resp_from.__name__
+# if from_whom != self:
+# self.status(f'''ring ring!
+# @{self}: *picks up phone*
+# @{from_whom}: I have a message I need you to send for me.
+# @{self}: To whom?
+# @{from_whom}: To @{to_whom}. But not directly.
+# @{self}: Who should it I pass it through?
+# @{from_whom}: Pass it to {nxt}. Tell them to use "{nxtfunc}".
+# @{self}: Got it... So what's the message?
+# @{from_whom}: The message is:
+# {dict_format(msg,tab=4)}
+# ''')
+ if caller!=self:
+ self.log(f'ring ring! I ({self}) have received a message from {caller},\n which I will now encrypt and send on to {to_whom}.')
+ else:
+ self.log(f'I ({self}) will now compose and send an encrypted message to {to_whom}.')
-The message is:
+ if route and type(msg)==dict and not ROUTE_KEYNAME in msg:
+ msg[ROUTE_KEYNAME] = route
- {dict_format(msg)}
-''')
-
# get encr msg obj
+
msg_obj = self.compose_msg_to(
msg,
- to_whom,
- route=route
+ to_whom
)
- self.log(f'ring ring! here is the message object I made, to send to {to_whom}: {msg_obj}')
+ self.log(f'Here is the message object I ({self}) made, to send to {to_whom}: {msg_obj}')
# encrypting
msg_obj.encrypt()
# pass through the telephone wire by the get_resp_from function
if not get_resp_from: get_resp_from=to_whom.ring_ring
- resp_msg_obj = get_resp_from(msg_obj.msg_d,from_whom=from_whom)
+ resp_msg_obj = get_resp_from(msg_obj.msg_d,caller=caller)
self.log('resp_msg_obj <-',resp_msg_obj)
# decrypt
@@ -243,7 +248,7 @@ The message is:
# route_response = self.route_msg(msg_obj)
# self.log('route_response',route_response)
# # set this to be the new msg
- # #msg_obj.msg = msg_obj.msg_d['_msg'] = response
+ # #msg_obj.msg = msg_obj.msg_d['msg'] = response
# #self.log('what msg_obj looks like now:',msg_obj)
# # send new content back
diff --git a/komrade/backend/people.py b/komrade/backend/people.py
index 15377ac..42e1985 100644
--- a/komrade/backend/people.py
+++ b/komrade/backend/people.py
@@ -60,7 +60,7 @@ class Persona(Caller):
## 2) Make pub public/private keys
keypair = KomradeAsymmetricKey()
pubkey,privkey = keypair.pubkey_obj,keypair.privkey_obj
- self.log(f'Keymaker has cut private and public keys:\n\n(1) {pubkey}\n\n(2) {privkey}')
+ self.log(f'@Keymaker has cut private and public keys:\n\n(1) {pubkey}\n\n(2) {privkey}')
## 3) Have passphrase?
if SHOW_STATUS and not passphrase:
@@ -70,7 +70,7 @@ class Persona(Caller):
## 4) Get hashed password
passhash = hasher(passphrase)
- self.log(f'''Keymaker has created a symmetric encryption cell using the disguised password:\n\n\t(2A) [Symmetric Encryption Key]\n\t({make_key_discreet_str(passhash)})''')
+ self.log(f'''@Keymaker has created a symmetric encryption cell using the disguised password:\n\n\t(2A) [Symmetric Encryption Key]\n\t({make_key_discreet_str(passhash)})''')
## 5) Encrypt private key
privkey_decr = KomradeSymmetricKeyWithPassphrase(passphrase)
@@ -97,21 +97,29 @@ class Persona(Caller):
## 7) Save data to server
data = {
'name':name,
- 'pubkey': pubkey
+ 'pubkey': pubkey.data,
}
- self.log('I will be sending this data to @TheOperator, on the remote server:',dict_format(data,tab=2))
+ # self.log('I will be sending this data to @TheOperator, on the remote server:',dict_format(data,tab=2))
# ring operator
# call from phone since I don't have pubkey on record on Op yet
# self.log('my keychain:',self._keychain,pubkey,self.op._keychain)
- resp_msg_obj = self.ring_ring(data,route='register_new_user',from_whom=self)
+ resp_msg_obj = self.ring_ring(
+ {
+ 'name':name,
+ 'pubkey': pubkey.data,
+ },
+ route='register_new_user'
+ )
self.log('register got back from op:',dict_format(resp_msg_obj,tab=2))
- def ring_ring(self,msg,**y):
- return super().ring_ring(msg,**y)
+ def ring_ring(self,msg,route=None,**y):
+ if type(msg)==dict and not ROUTE_KEYNAME in msg:
+ msg[ROUTE_KEYNAME]=route
+ return super().ring_ring(msg,caller=self,**y)
def send_msg_to(self,msg,to_whom):
msg = self.compose_msg_to(msg,to_whom)
@@ -142,6 +150,6 @@ if __name__=='__main__':
# # print(person.pubkey)
# # elon.send_msg_to('youre dumb',marx)
- # #Caller('elon').ring_ring({'_route':'say_hello','_msg':'my dumb message to operator'})
+ # #Caller('elon').ring_ring({'_route':'say_hello','msg':'my dumb message to operator'})
# # print(marx.exists_on_server())
\ No newline at end of file
diff --git a/komrade/backend/phonelines.py b/komrade/backend/phonelines.py
index b34e4a2..a84d351 100644
--- a/komrade/backend/phonelines.py
+++ b/komrade/backend/phonelines.py
@@ -65,15 +65,18 @@ def create_phonelines():
from base64 import b64encode
builtin_keys_b = pickle.dumps(builtin_keys)
- omega_key = KomradeSymmetricKeyWithoutPassphrase()
- builtin_keys_b_encr = omega_key.encrypt(builtin_keys_b)
- builtin_keys_b_encr_with_key = omega_key.data + BSEP + builtin_keys_b_encr
- builtin_keys_b_encr_with_key_b64 = b64encode(builtin_keys_b_encr_with_key)
+ # omega_key = KomradeSymmetricKeyWithoutPassphrase()
+ # builtin_keys_b_encr = omega_key.encrypt(builtin_keys_b)
+ # builtin_keys_b_encr_with_key = omega_key.data + BSEP + builtin_keys_b_encr
+ # builtin_keys_b_encr_with_key_b64 = b64encode(builtin_keys_b_encr_with_key)
+ builtin_keys_b64 = b64encode(builtin_keys_b)
with open(PATH_BUILTIN_KEYCHAIN,'wb') as of:
- of.write(builtin_keys_b_encr_with_key_b64)
+ of.write(builtin_keys_b64)
+ # of.write(builtin_keys_b_encr_with_key_b64)
print('>> saved:',PATH_BUILTIN_KEYCHAIN)
- print(builtin_keys_b_encr_with_key_b64)
+ # print(builtin_keys_b_encr_with_key_b64)
+ print(builtin_keys_b64)
@@ -107,12 +110,13 @@ def check_phonelines():
# builtins
with open(PATH_BUILTIN_KEYCHAIN,'rb') as f:
- builtin_keys_encr_b64 = f.read()
- builtin_keys_encr = b64decode(builtin_keys_encr_b64)
- omega_key_b,builtin_keys_encr = builtin_keys_encr.split(BSEP)
- omega_key = KomradeSymmetricKeyWithoutPassphrase(omega_key_b)
- builtin_keys_b = omega_key.decrypt(builtin_keys_encr)
- builtin_keys = pickle.loads(builtin_keys_b)
+ # builtin_keys_encr_b64 = f.read()
+ builtin_keys_b64 = f.read()
+ # builtin_keys_encr = b64decode(builtin_keys_encr_b64)
+ # omega_key_b,builtin_keys_encr = builtin_keys_encr.split(BSEP)
+ # omega_key = KomradeSymmetricKeyWithoutPassphrase(omega_key_b)
+ # builtin_keys_b = omega_key.decrypt(builtin_keys_encr)
+ builtin_keys = pickle.loads(b64decode(builtin_keys_b64))
# print(builtin_keys)
for name in builtin_keys:
diff --git a/komrade/backend/the_telephone.py b/komrade/backend/the_telephone.py
index 23eef4e..0738a96 100644
--- a/komrade/backend/the_telephone.py
+++ b/komrade/backend/the_telephone.py
@@ -19,7 +19,7 @@ class TheTelephone(Operator):
# def find_pubkey(self):
# return self.telephone_keychain.get('pubkey')
- def send_and_receive(self,msg_d):
+ def send_and_receive(self,msg_d,**y):
# seal for transport
msg_b_sealed = self.seal_msg(msg_d)
diff --git a/komrade/constants.py b/komrade/constants.py
index 0e4a661..6d2b623 100644
--- a/komrade/constants.py
+++ b/komrade/constants.py
@@ -33,8 +33,8 @@ BSEP=b'||||||||||'
BSEP2=b'@@@@@@@@@@'
BSEP3=b'##########'
-OPERATOR_NAME = 'TheOperator'
-TELEPHONE_NAME = 'TheTelephone'
+OPERATOR_NAME = 'Operator'
+TELEPHONE_NAME = 'Telephone'
WORLD_NAME = 'komrades'
PATH_APP = os.path.abspath(os.path.dirname(__file__))
# PATH_BUILTIN_KEYCHAINS_ENCR = os.path.join(PATH_APP,'.builtin.keychains.encr')
@@ -131,7 +131,7 @@ ALLOW_CLEARNET = True
DEBUG_DEFAULT_PASSPHRASE = None # 'all your base are belong to us'
-ROUTE_KEYNAME = '_route'
+ROUTE_KEYNAME = 'request'
OPERATOR_ROUTES = [
'forge_new_keys',
diff --git a/komrade/utils.py b/komrade/utils.py
index 4845822..8e260b2 100644
--- a/komrade/utils.py
+++ b/komrade/utils.py
@@ -158,6 +158,22 @@ def isBase64(sb):
return False
+import inspect,functools
+def get_class_that_defined_method(meth):
+ if isinstance(meth, functools.partial):
+ return get_class_that_defined_method(meth.func)
+ if inspect.ismethod(meth) or (inspect.isbuiltin(meth) and getattr(meth, '__self__', None) is not None and getattr(meth.__self__, '__class__', None)):
+ for cls in inspect.getmro(meth.__self__.__class__):
+ if meth.__name__ in cls.__dict__:
+ return cls
+ meth = getattr(meth, '__func__', meth) # fallback to __qualname__ parsing
+ if inspect.isfunction(meth):
+ cls = getattr(inspect.getmodule(meth),
+ meth.__qualname__.split('.', 1)[0].rsplit('.', 1)[0],
+ None)
+ if isinstance(cls, type):
+ return cls
+ return getattr(meth, '__objclass__', None) # handle special descriptor objects
def hashish(binary_data):