Add usumbufu hoba capable opener object
This commit is contained in:
parent
e3c002082b
commit
8568e352be
@ -13,6 +13,7 @@ from chainlib.chain import ChainSpec
|
|||||||
import clicada.cli.user as cmd_user
|
import clicada.cli.user as cmd_user
|
||||||
import clicada.cli.tag as cmd_tag
|
import clicada.cli.tag as cmd_tag
|
||||||
from clicada.cli.auth import PGPAuthCrypt
|
from clicada.cli.auth import PGPAuthCrypt
|
||||||
|
from clicada.cli.http import HTTPSession
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
data_dir = os.path.join(script_dir, '..', 'data')
|
data_dir = os.path.join(script_dir, '..', 'data')
|
||||||
@ -68,9 +69,12 @@ class CmdCtrl:
|
|||||||
else:
|
else:
|
||||||
self.config = chainlib.eth.cli.Config.from_args(self.cmd_args, base_config_dir=base_config_dir, extra_args=extra_args)
|
self.config = chainlib.eth.cli.Config.from_args(self.cmd_args, base_config_dir=base_config_dir, extra_args=extra_args)
|
||||||
|
|
||||||
self.__auth = self.auth(self.get('AUTH_TYPE'))
|
self.auth(self.get('AUTH_TYPE'))
|
||||||
|
|
||||||
self.config.add(False, '_SEQ')
|
self.config.add(False, '_SEQ')
|
||||||
|
|
||||||
|
self.config.censor('AUTH_PASSPHRASE')
|
||||||
|
|
||||||
logger.debug('loaded config:\n{}'.format(self.config))
|
logger.debug('loaded config:\n{}'.format(self.config))
|
||||||
|
|
||||||
self.chain_spec = ChainSpec.from_chain_str(self.config.get('CHAIN_SPEC'))
|
self.chain_spec = ChainSpec.from_chain_str(self.config.get('CHAIN_SPEC'))
|
||||||
@ -78,6 +82,9 @@ class CmdCtrl:
|
|||||||
self.rpc = chainlib.eth.cli.Rpc()
|
self.rpc = chainlib.eth.cli.Rpc()
|
||||||
self.__conn = self.rpc.connect_by_config(self.config)
|
self.__conn = self.rpc.connect_by_config(self.config)
|
||||||
|
|
||||||
|
self.remote_openers = {
|
||||||
|
'meta': HTTPSession(self.get('META_URL'), auth=self.__auth),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def auth(self, typ):
|
def auth(self, typ):
|
||||||
@ -110,3 +117,7 @@ class CmdCtrl:
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
self.cmd_mod.execute(self)
|
self.cmd_mod.execute(self)
|
||||||
|
|
||||||
|
|
||||||
|
def opener(self, k):
|
||||||
|
return self.remote_openers[k]
|
||||||
|
@ -5,6 +5,7 @@ import logging
|
|||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
import gnupg
|
import gnupg
|
||||||
|
from usumbufu.client.hoba import HobaClientSession
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from clicada.error import AuthError
|
from clicada.error import AuthError
|
||||||
@ -12,7 +13,10 @@ from clicada.error import AuthError
|
|||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PGPAuthCrypt:
|
class PGPAuthCrypt(HobaClientSession):
|
||||||
|
|
||||||
|
typ = 'gnupg'
|
||||||
|
alg = '969'
|
||||||
|
|
||||||
def __init__(self, db_dir, auth_key, pgp_dir=None):
|
def __init__(self, db_dir, auth_key, pgp_dir=None):
|
||||||
self.db_dir = db_dir
|
self.db_dir = db_dir
|
||||||
@ -51,3 +55,21 @@ class PGPAuthCrypt:
|
|||||||
if not self.secret.ok:
|
if not self.secret.ok:
|
||||||
raise AuthError('could not decrypt encryption secret. wrong password?')
|
raise AuthError('could not decrypt encryption secret. wrong password?')
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def sign_auth_challenge(self, plaintext, hoba, encoding):
|
||||||
|
r = self.gpg.sign(plaintext, passphrase=self.passphrase, detach=True)
|
||||||
|
|
||||||
|
if encoding == 'base64':
|
||||||
|
r = r.data
|
||||||
|
|
||||||
|
hoba.signature = r
|
||||||
|
return str(hoba)
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'clicada hoba/pgp auth'
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'clicada hoba/pgp auth'
|
||||||
|
52
clicada/cli/http.py
Normal file
52
clicada/cli/http.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# standard imports
|
||||||
|
import hashlib
|
||||||
|
import urllib.parse
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# external imports
|
||||||
|
from usumbufu.client.base import (
|
||||||
|
ClientSession,
|
||||||
|
BaseTokenStore,
|
||||||
|
)
|
||||||
|
from usumbufu.client.bearer import BearerClientSession
|
||||||
|
|
||||||
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPSession:
|
||||||
|
|
||||||
|
token_dir = '/run/user/{}/clicada/usumbufu/.token'.format(os.getuid())
|
||||||
|
|
||||||
|
def __init__(self, url, auth=None):
|
||||||
|
logg.debug('auth auth {}'.format(auth))
|
||||||
|
self.base_url = url
|
||||||
|
url_parts = urllib.parse.urlparse(self.base_url)
|
||||||
|
self.origin = urllib.parse.urljoin(url_parts[0], url_parts[1])
|
||||||
|
|
||||||
|
h = hashlib.sha256()
|
||||||
|
h.update(self.base_url.encode('utf-8'))
|
||||||
|
z = h.digest()
|
||||||
|
|
||||||
|
token_store_dir = os.path.join(self.token_dir, z.hex())
|
||||||
|
self.token_store = BaseTokenStore(path=token_store_dir)
|
||||||
|
|
||||||
|
self.session = ClientSession(self.origin, token_store=self.token_store)
|
||||||
|
bearer_handler = BearerClientSession(self.origin, token_store=self.token_store)
|
||||||
|
self.session.add_subhandler(bearer_handler)
|
||||||
|
|
||||||
|
if auth != None:
|
||||||
|
self.session.add_subhandler(auth)
|
||||||
|
|
||||||
|
self.opener = urllib.request.build_opener(self.session)
|
||||||
|
|
||||||
|
|
||||||
|
def open(self, endpoint):
|
||||||
|
url = urllib.parse.urljoin(self.base_url, endpoint)
|
||||||
|
logg.debug('open {} with opener {}'.format(url, self))
|
||||||
|
r = self.opener.open(url)
|
||||||
|
return r.read().decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.session)
|
@ -26,7 +26,7 @@ logg = logging.getLogger(__name__)
|
|||||||
def process_args(argparser):
|
def process_args(argparser):
|
||||||
argparser.add_argument('-m', '--method', type=str, help='lookup method')
|
argparser.add_argument('-m', '--method', type=str, help='lookup method')
|
||||||
argparser.add_argument('--meta-url', dest='meta_url', type=str, help='Url to retrieve metadata from')
|
argparser.add_argument('--meta-url', dest='meta_url', type=str, help='Url to retrieve metadata from')
|
||||||
argparser.add_argument('-f', '--force-update', dest='force_update', type=str, help='Update records of mutable entries')
|
argparser.add_argument('-f', '--force-update', dest='force_update', action='store_true', help='Update records of mutable entries')
|
||||||
argparser.add_argument('identifier', type=str, help='user identifier')
|
argparser.add_argument('identifier', type=str, help='user identifier')
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ def execute(ctrl):
|
|||||||
|
|
||||||
store_path = '.clicada'
|
store_path = '.clicada'
|
||||||
user_phone_file_label = 'phone'
|
user_phone_file_label = 'phone'
|
||||||
user_phone_store = FileUserStore(ctrl.chain(), user_phone_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
user_phone_store = FileUserStore(ctrl.opener('meta'), ctrl.chain(), user_phone_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
||||||
|
|
||||||
user_address = user_phone_store.by_phone(ctrl.get('_IDENTIFIER'), update=ctrl.get('_FORCE'))
|
user_address = user_phone_store.by_phone(ctrl.get('_IDENTIFIER'), update=ctrl.get('_FORCE'))
|
||||||
if user_address == None:
|
if user_address == None:
|
||||||
@ -74,9 +74,9 @@ def execute(ctrl):
|
|||||||
token_store = FileTokenStore(ctrl.chain(), ctrl.conn(), 'token', store_path)
|
token_store = FileTokenStore(ctrl.chain(), ctrl.conn(), 'token', store_path)
|
||||||
|
|
||||||
user_address_file_label = 'address'
|
user_address_file_label = 'address'
|
||||||
user_address_store = FileUserStore(ctrl.chain(), user_address_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
user_address_store = FileUserStore(ctrl.opener('meta'), ctrl.chain(), user_address_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
||||||
|
|
||||||
r = user_address_store.by_address(user_address)
|
r = user_address_store.by_address(user_address, update=ctrl.get('_FORCE'))
|
||||||
|
|
||||||
print("""Phone: {}
|
print("""Phone: {}
|
||||||
Network address: {}
|
Network address: {}
|
||||||
|
@ -33,12 +33,13 @@ class Account(Person):
|
|||||||
|
|
||||||
def apply_custom(self, custom_data):
|
def apply_custom(self, custom_data):
|
||||||
self.tags = custom_data['tags']
|
self.tags = custom_data['tags']
|
||||||
|
logg.debug('tags are now {}'.format(self.tags))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FileUserStore:
|
class FileUserStore:
|
||||||
|
|
||||||
def __init__(self, chain_spec, label, store_base_path, ttl):
|
def __init__(self, metadata_opener, chain_spec, label, store_base_path, ttl):
|
||||||
invalidate_before = datetime.datetime.now() - datetime.timedelta(seconds=ttl)
|
invalidate_before = datetime.datetime.now() - datetime.timedelta(seconds=ttl)
|
||||||
self.invalidate_before = int(invalidate_before.timestamp())
|
self.invalidate_before = int(invalidate_before.timestamp())
|
||||||
self.have_xattr = False
|
self.have_xattr = False
|
||||||
@ -53,6 +54,7 @@ class FileUserStore:
|
|||||||
self.memstore_entity = MemDictStore()
|
self.memstore_entity = MemDictStore()
|
||||||
os.makedirs(self.store_path, exist_ok=True)
|
os.makedirs(self.store_path, exist_ok=True)
|
||||||
self.__validate_dir()
|
self.__validate_dir()
|
||||||
|
self.metadata_opener = metadata_opener
|
||||||
|
|
||||||
|
|
||||||
def __validate_dir(self):
|
def __validate_dir(self):
|
||||||
@ -177,7 +179,7 @@ class FileUserStore:
|
|||||||
logg.debug('no address found for phone {}: {}'.format(phone, e))
|
logg.debug('no address found for phone {}: {}'.format(phone, e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.put(phone_file, user_address)
|
self.put(phone_file, user_address, force=update)
|
||||||
return user_address
|
return user_address
|
||||||
|
|
||||||
|
|
||||||
@ -189,12 +191,12 @@ class FileUserStore:
|
|||||||
try:
|
try:
|
||||||
v = self.get(address, ignore_expired=ignore_expired)
|
v = self.get(address, ignore_expired=ignore_expired)
|
||||||
v = json.loads(v)
|
v = json.loads(v)
|
||||||
person = Person()
|
person = Account()
|
||||||
try:
|
try:
|
||||||
person_data = person.deserialize(person_data=v)
|
person_data = person.deserialize(person_data=v)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
person_data = v
|
person_data = v
|
||||||
return str(person_data)
|
return person_data
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
except ExpiredRecordError as e:
|
except ExpiredRecordError as e:
|
||||||
@ -202,25 +204,28 @@ class FileUserStore:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
address = strip_0x(address)
|
address = strip_0x(address)
|
||||||
getter = MetadataRequestsHandler(MetadataPointer.PERSON, bytes.fromhex(address))
|
getter = self.metadata_opener
|
||||||
|
|
||||||
|
ptr = generate_metadata_pointer(bytes.fromhex(address), MetadataPointer.PERSON)
|
||||||
r = None
|
r = None
|
||||||
try:
|
try:
|
||||||
r = getter.query()
|
r = getter.open(ptr)
|
||||||
except requests.exceptions.HTTPError as e:
|
except Exception as e:
|
||||||
logg.debug('no metadata found for {}: {}'.format(address, e))
|
logg.debug('no metadata found for {}: {}'.format(address, e))
|
||||||
return address
|
return address
|
||||||
|
|
||||||
data = r.json()
|
data = json.loads(r)
|
||||||
person = Account()
|
person = Account()
|
||||||
person_data = person.deserialize(person_data=data)
|
person_data = person.deserialize(person_data=data)
|
||||||
self.put(address, json.dumps(person_data.serialize()))
|
self.put(address, json.dumps(person_data.serialize()), force=update)
|
||||||
|
|
||||||
getter = MetadataRequestsHandler(MetadataPointer.CUSTOM, bytes.fromhex(address))
|
ptr = generate_metadata_pointer(bytes.fromhex(address), MetadataPointer.CUSTOM)
|
||||||
r = None
|
r = None
|
||||||
try:
|
try:
|
||||||
r = getter.query()
|
r = getter.open(ptr)
|
||||||
person_data.apply_custom(r.json())
|
o = json.loads(r)
|
||||||
except requests.exceptions.HTTPError as e:
|
person_data.apply_custom(o)
|
||||||
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return person_data
|
return person_data
|
||||||
|
Loading…
Reference in New Issue
Block a user