aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--b4/__init__.py3
-rw-r--r--b4/command.py2
-rw-r--r--b4/mbox.py73
3 files changed, 77 insertions, 1 deletions
diff --git a/b4/__init__.py b/b4/__init__.py
index 59dfccf..12afe94 100644
--- a/b4/__init__.py
+++ b/b4/__init__.py
@@ -1027,7 +1027,8 @@ class LoreMessage:
attestations = patatt.validate_message(self.msg.as_bytes(), sources)
for passing, identity, signtime, keysrc, keyalgo, errors in attestations:
- attestor = LoreAttestorPatatt(passing, identity, signtime, keysrc, keyalgo, errors)
+ signdt = LoreAttestor.parse_ts(signtime)
+ attestor = LoreAttestorPatatt(passing, identity, signdt, keysrc, keyalgo, errors)
self._attestors.append(attestor)
def get_attestation_trailers(self, attpolicy: str, maxdays: int = 0) -> Tuple[str, list, bool]:
diff --git a/b4/command.py b/b4/command.py
index ff457dd..12c7354 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -84,6 +84,8 @@ def cmd():
cmd_mbox_common_opts(sp_mbox)
sp_mbox.add_argument('-f', '--filter-dupes', dest='filterdupes', action='store_true', default=False,
help='When adding messages to existing maildir, filter out duplicates')
+ sp_mbox.add_argument('--show-keys', dest='showkeys', action='store_true', default=False,
+ help='Show all developer keys from the thread')
sp_mbox.set_defaults(func=cmd_mbox)
# b4 am
diff --git a/b4/mbox.py b/b4/mbox.py
index 275a42a..7804535 100644
--- a/b4/mbox.py
+++ b/b4/mbox.py
@@ -16,6 +16,7 @@ import time
import json
import fnmatch
import shutil
+import pathlib
import urllib.parse
import xml.etree.ElementTree
@@ -534,6 +535,78 @@ def main(cmdargs):
return
mbx = mailbox.mbox(threadfile)
+
+ if cmdargs.showkeys:
+ logger.info('---')
+ try:
+ import patatt
+ except ModuleNotFoundError:
+ logger.info('--show-keys requires patatt library')
+ sys.exit(1)
+
+ keydata = set()
+ for msg in mbx:
+ xdk = msg.get('x-developer-key')
+ xds = msg.get('x-developer-signature')
+ if not xdk or not xds:
+ continue
+ # grab the selector they used
+ kdata = b4.LoreMessage.get_parts_from_header(xdk)
+ sdata = b4.LoreMessage.get_parts_from_header(xds)
+ algo = kdata.get('a')
+ identity = kdata.get('i')
+ selector = sdata.get('s', 'default')
+ if algo == 'openpgp':
+ keyinfo = kdata.get('fpr')
+ elif algo == 'ed25519':
+ keyinfo = kdata.get('pk')
+ else:
+ logger.debug('Unknown key type: %s', algo)
+ continue
+ keydata.add((identity, algo, selector, keyinfo))
+ if not keydata:
+ logger.info('No keys found in the thread.')
+ sys.exit(0)
+ krpath = os.path.join(b4.get_data_dir(), 'keyring')
+ pgp = False
+ ecc = False
+ for identity, algo, selector, keyinfo in keydata:
+ keypath = patatt.make_pkey_path(algo, identity, selector)
+ fullpath = os.path.join(krpath, keypath)
+ if os.path.exists(fullpath):
+ status = 'known'
+ else:
+ if algo == 'openpgp':
+ uids = b4.get_gpg_uids(keyinfo)
+ if len(uids):
+ status = 'in default keyring'
+ else:
+ status = 'unknown'
+ else:
+ status = 'unknown'
+ pathlib.Path(os.path.dirname(fullpath)).mkdir(parents=True, exist_ok=True)
+
+ logger.info('%s: (%s)', identity, status)
+ logger.info(' keytype: %s', algo)
+ if algo == 'openpgp':
+ pgp = True
+ logger.info(' keyid: %s', keyinfo[-16:])
+ logger.info(' fpr: %s', ':'.join(re.findall(r'.{4}', keyinfo)))
+ else:
+ ecc = True
+ logger.info(' pubkey: %s', keyinfo)
+ logger.info(' krpath: %s', keypath)
+ logger.info(' fullpath: %s', fullpath)
+ logger.info('---')
+ if pgp:
+ logger.info('For openpgp keys:')
+ logger.info(' gpg --recv-key [keyid]')
+ logger.info(' gpg -a --export [keyid] > [fullpath]')
+ if ecc:
+ logger.info('For ed25519 keys:')
+ logger.info(' echo [pubkey] > [fullpath]')
+ sys.exit(0)
+
logger.info('%s messages in the thread', len(mbx))
if cmdargs.outdir == '-':
mbx.close()