Add pgp auth, subject metadata summary in cli user output
This commit is contained in:
parent
76b331178c
commit
bdfdd0fdd7
@ -12,6 +12,7 @@ from chainlib.chain import ChainSpec
|
||||
# local imports
|
||||
import clicada.cli.user as cmd_user
|
||||
import clicada.cli.tag as cmd_tag
|
||||
from clicada.cli.auth import PGPAuthCrypt
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
data_dir = os.path.join(script_dir, '..', 'data')
|
||||
@ -25,13 +26,12 @@ class CmdCtrl:
|
||||
't': 'tag',
|
||||
}
|
||||
|
||||
def __init__(self, argv=None, description=None, logger=None, *args, **kwargs):
|
||||
#self.argparser = argparse.ArgumentParser(description=description, *args, **kwargs)
|
||||
self.argparser = chainlib.eth.cli.ArgumentParser(chainlib.eth.cli.argflag_std_read)
|
||||
__auth_for = [
|
||||
'user',
|
||||
]
|
||||
|
||||
#self.argparser.add_argument('-c', type=str, help='Configuration override directory path')
|
||||
#self.argparser.add_argument('-v', action='store_true', help='Be verbose')
|
||||
#self.argparser.add_argument('-vv', action='store_true', help='Be very verbose')
|
||||
def __init__(self, argv=None, description=None, logger=None, *args, **kwargs):
|
||||
self.argparser = chainlib.eth.cli.ArgumentParser(chainlib.eth.cli.argflag_std_read)
|
||||
|
||||
sub = self.argparser.add_subparsers()
|
||||
sub.dest = 'command'
|
||||
@ -68,6 +68,8 @@ 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.config.add(False, '_SEQ')
|
||||
logger.debug('loaded config:\n{}'.format(self.config))
|
||||
|
||||
@ -77,8 +79,18 @@ class CmdCtrl:
|
||||
self.__conn = self.rpc.connect_by_config(self.config)
|
||||
|
||||
|
||||
def get(self, k):
|
||||
r = self.config.get(k)
|
||||
|
||||
def auth(self, typ):
|
||||
if typ != 'gnupg':
|
||||
raise NotImplementedError('Valid aut implementations are: gnupg')
|
||||
default_auth_db_path = os.path.join(os.environ['HOME'], '.clicada/auth')
|
||||
auth_db_path = self.get('AUTH_DB_PATH', default_auth_db_path)
|
||||
self.__auth = PGPAuthCrypt(auth_db_path, self.get('AUTH_KEY'), self.get('AUTH_KEYRING_PATH'))
|
||||
self.__auth.get_secret(self.get('AUTH_PASSPHRASE'))
|
||||
|
||||
|
||||
def get(self, k, default=None):
|
||||
r = self.config.get(k, default)
|
||||
if k in [
|
||||
'_FORCE',
|
||||
]:
|
||||
|
53
clicada/cli/auth.py
Normal file
53
clicada/cli/auth.py
Normal file
@ -0,0 +1,53 @@
|
||||
# standard imports
|
||||
import os
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
import gnupg
|
||||
|
||||
# local imports
|
||||
from clicada.error import AuthError
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PGPAuthCrypt:
|
||||
|
||||
def __init__(self, db_dir, auth_key, pgp_dir=None):
|
||||
self.db_dir = db_dir
|
||||
try:
|
||||
bytes.fromhex(auth_key)
|
||||
except TypeError:
|
||||
raise AuthError('invalid key {}'.format(auth_key))
|
||||
except ValueError:
|
||||
raise AuthError('invalid key {}'.format(auth_key))
|
||||
self.auth_key = auth_key
|
||||
self.gpg = gnupg.GPG(gnupghome=pgp_dir)
|
||||
|
||||
|
||||
def get_secret(self, passphrase=''):
|
||||
if passphrase == None:
|
||||
passphrase = ''
|
||||
p = os.path.join(self.db_dir, '.secret')
|
||||
try:
|
||||
f = open(p, 'rb')
|
||||
except FileNotFoundError:
|
||||
h = hashlib.sha256()
|
||||
h.update(bytes.fromhex(self.auth_key))
|
||||
h.update(passphrase.encode('utf-8'))
|
||||
z = h.digest()
|
||||
secret = self.gpg.encrypt(z, [self.auth_key])
|
||||
if not secret.ok:
|
||||
raise AuthError('could not encrypt secret for {}'.format(auth_key))
|
||||
|
||||
d = os.path.dirname(p)
|
||||
os.makedirs(d, exist_ok=True)
|
||||
f = open(p, 'wb')
|
||||
f.write(secret.data)
|
||||
f.close()
|
||||
f = open(p, 'rb')
|
||||
self.secret = self.gpg.decrypt_file(f, passphrase=passphrase)
|
||||
if not self.secret.ok:
|
||||
raise AuthError('could not decrypt encryption secret. wrong password?')
|
||||
f.close()
|
@ -1,11 +1,13 @@
|
||||
# standard imports
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
# external imports
|
||||
from cic_eth_registry import CICRegistry
|
||||
from cic_eth_registry.lookup.tokenindex import TokenIndexLookup
|
||||
from cic_types.ext.metadata import MetadataRequestsHandler
|
||||
from cic_types.models.person import Person
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
|
||||
# local imports
|
||||
@ -29,7 +31,7 @@ def extra_args():
|
||||
'force_update': '_FORCE',
|
||||
'method': 'META_LOOKUP_METHOD',
|
||||
'meta_url': 'META_URL',
|
||||
'identifier': '_ARG_USER_IDENTIFIER',
|
||||
'identifier': '_IDENTIFIER',
|
||||
}
|
||||
|
||||
|
||||
@ -51,18 +53,17 @@ def execute(ctrl):
|
||||
user_phone_file_label = 'phone'
|
||||
user_phone_store = FileUserStore(ctrl.chain(), user_phone_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
||||
|
||||
user_address = user_phone_store.by_phone(ctrl.get('_ARG_USER_IDENTIFIER'), update=ctrl.get('_FORCE'))
|
||||
user_address = user_phone_store.by_phone(ctrl.get('_IDENTIFIER'), update=ctrl.get('_FORCE'))
|
||||
if user_address == None:
|
||||
sys.stderr.write('unknown identifier: {}\n'.format(ctrl.get('_ARG_USER_IDENTIFIER')))
|
||||
sys.stderr.write('unknown identifier: {}\n'.format(ctrl.get('_IDENTIFIER')))
|
||||
sys.exit(1)
|
||||
try:
|
||||
user_address = to_checksum_address(user_address)
|
||||
except ValueError:
|
||||
sys.stderr.write('invalid response "{}" for {}\n'.format(user_address, ctrl.get('_ARG_USER_IDENTIFIER')))
|
||||
sys.stderr.write('invalid response "{}" for {}\n'.format(user_address, ctrl.get('_IDENTIFIER')))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
logg.debug('loaded user address {} for {}'.format(user_address, ctrl.get('_ARG_USER_IDENTIFIER')))
|
||||
logg.debug('loaded user address {} for {}'.format(user_address, ctrl.get('_IDENTIFIER')))
|
||||
|
||||
txs = tx_getter.get(user_address)
|
||||
|
||||
@ -71,6 +72,27 @@ def execute(ctrl):
|
||||
user_address_file_label = 'address'
|
||||
user_address_store = FileUserStore(ctrl.chain(), user_address_file_label, store_path, int(ctrl.get('FILESTORE_TTL')))
|
||||
|
||||
r = user_address_store.by_address(user_address)
|
||||
|
||||
print("""Phone: {}
|
||||
EVM address: {}
|
||||
Name: {}
|
||||
Registered: {}
|
||||
Gender: {}
|
||||
Location: {}
|
||||
Products: {}
|
||||
""".format(
|
||||
ctrl.get('_IDENTIFIER'),
|
||||
user_address,
|
||||
str(r),
|
||||
datetime.datetime.fromtimestamp(r.date_registered).ctime(),
|
||||
r.gender,
|
||||
r.location['area_name'],
|
||||
','.join(r.products),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
for tx_src in txs['data']:
|
||||
tx = ResolvedTokenTx.from_dict(tx_src)
|
||||
tx.resolve(token_store, user_address_store, update=ctrl.get('_FORCE'))
|
||||
|
@ -10,3 +10,10 @@ cache_url =
|
||||
|
||||
[cic]
|
||||
registry_address =
|
||||
|
||||
[auth]
|
||||
type = gnupg
|
||||
db_path =
|
||||
keyring_path =
|
||||
key =
|
||||
passphrase =
|
||||
|
@ -1,2 +1,6 @@
|
||||
class ExpiredRecordError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AuthError(Exception):
|
||||
pass
|
||||
|
@ -69,14 +69,16 @@ class ResolvedTokenTx(TokenTx):
|
||||
return v
|
||||
if self.tx_type == TokenTxType.faucet_giveto.value:
|
||||
return 'FAUCET'
|
||||
return user_store.get_label(self.sender)
|
||||
r = user_store.by_address(self.sender)
|
||||
return str(r)
|
||||
|
||||
|
||||
def resolve_recipient_entity(self, user_store, update=False):
|
||||
v = self.resolve_stored_entity(user_store, self.recipient, update=update)
|
||||
if v != None:
|
||||
return v
|
||||
return user_store.get_label(self.recipient, update=update)
|
||||
r = user_store.by_address(self.recipient, update=update)
|
||||
return str(r)
|
||||
|
||||
|
||||
def resolve_entities(self, user_store, update=False):
|
||||
|
@ -169,7 +169,7 @@ class FileUserStore:
|
||||
return user_address
|
||||
|
||||
|
||||
def get_label(self, address, update=False):
|
||||
def by_address(self, address, update=False):
|
||||
add = tx_normalize.wallet_address(address)
|
||||
ignore_expired = self.sticky(address)
|
||||
|
||||
@ -202,4 +202,4 @@ class FileUserStore:
|
||||
person = Person()
|
||||
person_data = person.deserialize(person_data=data)
|
||||
self.put(address, json.dumps(person_data.serialize()))
|
||||
return str(person_data)
|
||||
return person_data
|
||||
|
Loading…
Reference in New Issue
Block a user