Add usumbufu hoba capable opener object

This commit is contained in:
nolash 2021-11-06 14:04:29 +01:00
parent e3c002082b
commit 8568e352be
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
5 changed files with 109 additions and 19 deletions

View File

@ -13,6 +13,7 @@ from chainlib.chain import ChainSpec
import clicada.cli.user as cmd_user
import clicada.cli.tag as cmd_tag
from clicada.cli.auth import PGPAuthCrypt
from clicada.cli.http import HTTPSession
script_dir = os.path.dirname(os.path.realpath(__file__))
data_dir = os.path.join(script_dir, '..', 'data')
@ -68,9 +69,12 @@ class CmdCtrl:
else:
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.censor('AUTH_PASSPHRASE')
logger.debug('loaded config:\n{}'.format(self.config))
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.__conn = self.rpc.connect_by_config(self.config)
self.remote_openers = {
'meta': HTTPSession(self.get('META_URL'), auth=self.__auth),
}
def auth(self, typ):
@ -110,3 +117,7 @@ class CmdCtrl:
def execute(self):
self.cmd_mod.execute(self)
def opener(self, k):
return self.remote_openers[k]

View File

@ -5,6 +5,7 @@ import logging
# external imports
import gnupg
from usumbufu.client.hoba import HobaClientSession
# local imports
from clicada.error import AuthError
@ -12,7 +13,10 @@ from clicada.error import AuthError
logg = logging.getLogger(__name__)
class PGPAuthCrypt:
class PGPAuthCrypt(HobaClientSession):
typ = 'gnupg'
alg = '969'
def __init__(self, db_dir, auth_key, pgp_dir=None):
self.db_dir = db_dir
@ -51,3 +55,21 @@ class PGPAuthCrypt:
if not self.secret.ok:
raise AuthError('could not decrypt encryption secret. wrong password?')
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
View 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)

View File

@ -26,7 +26,7 @@ logg = logging.getLogger(__name__)
def process_args(argparser):
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('-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')
@ -55,7 +55,7 @@ def execute(ctrl):
store_path = '.clicada'
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'))
if user_address == None:
@ -74,9 +74,9 @@ def execute(ctrl):
token_store = FileTokenStore(ctrl.chain(), ctrl.conn(), 'token', store_path)
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: {}
Network address: {}

View File

@ -33,12 +33,13 @@ class Account(Person):
def apply_custom(self, custom_data):
self.tags = custom_data['tags']
logg.debug('tags are now {}'.format(self.tags))
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)
self.invalidate_before = int(invalidate_before.timestamp())
self.have_xattr = False
@ -53,6 +54,7 @@ class FileUserStore:
self.memstore_entity = MemDictStore()
os.makedirs(self.store_path, exist_ok=True)
self.__validate_dir()
self.metadata_opener = metadata_opener
def __validate_dir(self):
@ -177,7 +179,7 @@ class FileUserStore:
logg.debug('no address found for phone {}: {}'.format(phone, e))
return None
self.put(phone_file, user_address)
self.put(phone_file, user_address, force=update)
return user_address
@ -189,12 +191,12 @@ class FileUserStore:
try:
v = self.get(address, ignore_expired=ignore_expired)
v = json.loads(v)
person = Person()
person = Account()
try:
person_data = person.deserialize(person_data=v)
except Exception as e:
person_data = v
return str(person_data)
return person_data
except FileNotFoundError:
pass
except ExpiredRecordError as e:
@ -202,25 +204,28 @@ class FileUserStore:
pass
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
try:
r = getter.query()
except requests.exceptions.HTTPError as e:
r = getter.open(ptr)
except Exception as e:
logg.debug('no metadata found for {}: {}'.format(address, e))
return address
data = r.json()
data = json.loads(r)
person = Account()
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
try:
r = getter.query()
person_data.apply_custom(r.json())
except requests.exceptions.HTTPError as e:
r = getter.open(ptr)
o = json.loads(r)
person_data.apply_custom(o)
except Exception as e:
pass
return person_data