keyringctl: Implement filtering of certifications
keyringctl: Add `get_fingerprints_from_import_source()` to derive all fingerprints of PGP public keys found in the import source. Add `get_fingerprints_from_decomposed_dir()` to derive all fingerprints of PGP public keys found in a directory structure holding decomposed PGP packet data. Add `get_fingerprints()` to derive a set of fingerprints of PGP public keys provided through `get_fingerprints_from_import_source()` and `get_fingerprints_from_decomposed_dir()`. Change `convert()` and `convert_certificate()` to accept an optional set of strings (`fingerprint_filter`) that may be used as a filter for valid fingerprints when considering certifications. Change `__main__` to call `convert()` when importing keys to packager or main dir, providing `fingerprint_filter` which will attempt to look up fingerprints in the source as well as the target.
This commit is contained in:
parent
4b70feb2fb
commit
49ff2df1fc
116
keyringctl
116
keyringctl
@ -13,7 +13,7 @@ from shutil import copytree
|
|||||||
from subprocess import PIPE, CalledProcessError, check_output
|
from subprocess import PIPE, CalledProcessError, check_output
|
||||||
from sys import exit, stderr
|
from sys import exit, stderr
|
||||||
from tempfile import TemporaryDirectory, mkdtemp
|
from tempfile import TemporaryDirectory, mkdtemp
|
||||||
from typing import Dict, Iterable, Iterator, List, Optional, Tuple, Union
|
from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
@ -118,6 +118,7 @@ def convert_certificate( # noqa: ignore=C901
|
|||||||
working_dir: Path,
|
working_dir: Path,
|
||||||
certificate: Path,
|
certificate: Path,
|
||||||
name_override: Optional[str] = None,
|
name_override: Optional[str] = None,
|
||||||
|
fingerprint_filter: Optional[Set[str]] = None,
|
||||||
) -> Path:
|
) -> Path:
|
||||||
"""Convert a single file public key certificate into a decomposed directory structure of multiple PGP packets
|
"""Convert a single file public key certificate into a decomposed directory structure of multiple PGP packets
|
||||||
|
|
||||||
@ -133,6 +134,9 @@ def convert_certificate( # noqa: ignore=C901
|
|||||||
The path to a public key certificate
|
The path to a public key certificate
|
||||||
name_override: Optional[str]
|
name_override: Optional[str]
|
||||||
An optional string to override the username in the to be created output directory structure
|
An optional string to override the username in the to be created output directory structure
|
||||||
|
fingerprint_filter: Optional[Set[str]]
|
||||||
|
An optional list of strings defining fingerprints of PGP public keys that all certificates will be filtered
|
||||||
|
with
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
------
|
------
|
||||||
@ -251,7 +255,11 @@ def convert_certificate( # noqa: ignore=C901
|
|||||||
elif signature_type == "PositiveCertification" and certificate_fingerprint.endswith(issuer):
|
elif signature_type == "PositiveCertification" and certificate_fingerprint.endswith(issuer):
|
||||||
uid_binding_sigs[current_packet_key] = packet
|
uid_binding_sigs[current_packet_key] = packet
|
||||||
elif signature_type.endswith("Certification"):
|
elif signature_type.endswith("Certification"):
|
||||||
certifications[current_packet_key].append(packet)
|
if fingerprint_filter is not None and any([fp.endswith(issuer) for fp in fingerprint_filter]):
|
||||||
|
debug(f"The certification by issuer {issuer} is appended as it is found in the filter.")
|
||||||
|
certifications[current_packet_key].append(packet)
|
||||||
|
else:
|
||||||
|
debug(f"The certification by issuer {issuer} is not appended because it is not in the filter")
|
||||||
else:
|
else:
|
||||||
raise Exception(f"unknown signature type: {signature_type}")
|
raise Exception(f"unknown signature type: {signature_type}")
|
||||||
elif current_packet_mode == "subkey":
|
elif current_packet_mode == "subkey":
|
||||||
@ -782,6 +790,7 @@ def convert(
|
|||||||
source: Path,
|
source: Path,
|
||||||
target_dir: Path,
|
target_dir: Path,
|
||||||
name_override: Optional[str] = None,
|
name_override: Optional[str] = None,
|
||||||
|
fingerprint_filter: Optional[Set[str]] = None,
|
||||||
) -> Path:
|
) -> Path:
|
||||||
"""Convert a path containing PGP certificate material to a decomposed directory structure
|
"""Convert a path containing PGP certificate material to a decomposed directory structure
|
||||||
|
|
||||||
@ -797,6 +806,8 @@ def convert(
|
|||||||
A directory path to write the new directory structure to
|
A directory path to write the new directory structure to
|
||||||
name_override: Optional[str]
|
name_override: Optional[str]
|
||||||
An optional username override for the call to `convert_certificate()`
|
An optional username override for the call to `convert_certificate()`
|
||||||
|
fingerprint_filter: Optional[Set[str]]
|
||||||
|
An optional set of strings defining fingerprints of PGP public keys that all certificates will be filtered with
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -814,7 +825,14 @@ def convert(
|
|||||||
or derive_user_from_target(working_dir=working_dir, target_dir=target_dir, certificate=cert)
|
or derive_user_from_target(working_dir=working_dir, target_dir=target_dir, certificate=cert)
|
||||||
or key.stem
|
or key.stem
|
||||||
)
|
)
|
||||||
directories.append(convert_certificate(working_dir=working_dir, certificate=cert, name_override=name))
|
directories.append(
|
||||||
|
convert_certificate(
|
||||||
|
working_dir=working_dir,
|
||||||
|
certificate=cert,
|
||||||
|
name_override=name,
|
||||||
|
fingerprint_filter=fingerprint_filter,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
for path in directories:
|
for path in directories:
|
||||||
(target_dir / path.name).mkdir(parents=True, exist_ok=True)
|
(target_dir / path.name).mkdir(parents=True, exist_ok=True)
|
||||||
@ -976,6 +994,88 @@ def export_revoked(certs: List[Path], main_keys: List[str], output: Path, min_re
|
|||||||
trusted_certs_file.write(f"{cert}\n")
|
trusted_certs_file.write(f"{cert}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_fingerprints_from_import_source(working_dir: Path, source: Path) -> List[str]:
|
||||||
|
"""Get all fingerprints of PGP public keys from import file(s)
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
working_dir: Path
|
||||||
|
A directory to use for temporary files
|
||||||
|
source: Path
|
||||||
|
The path to a source file or directory
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
List[str]
|
||||||
|
A list of strings representing the fingerprints of PGP public keys found in source
|
||||||
|
"""
|
||||||
|
|
||||||
|
fingerprints: List[str] = []
|
||||||
|
keys: List[Path] = list(source.iterdir()) if source.is_dir() else [source]
|
||||||
|
|
||||||
|
for key in keys:
|
||||||
|
for certificate in keyring_split(working_dir=working_dir, keyring=key):
|
||||||
|
for packet in packet_split(working_dir=working_dir, certificate=certificate):
|
||||||
|
if packet.name.endswith("--PublicKey"):
|
||||||
|
fingerprints += [packet_dump_field(packet, "Fingerprint")]
|
||||||
|
|
||||||
|
debug(f"Fingerprints of PGP public keys in {source}: {fingerprints}")
|
||||||
|
return fingerprints
|
||||||
|
|
||||||
|
|
||||||
|
def get_fingerprints_from_decomposed_dir(path: Path) -> List[str]:
|
||||||
|
"""Get all fingerprints of PGP public keys from a decomposed directory structure
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path: Path
|
||||||
|
The path to a decomposed directory structure
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
List[str]
|
||||||
|
A list of strings representing all fingerprints of PGP public keys below path
|
||||||
|
"""
|
||||||
|
|
||||||
|
fingerprints = [path.stem for path in list(path.absolute().glob("*/*"))]
|
||||||
|
debug(f"Fingerprints of PGP public keys in {path}: {fingerprints}")
|
||||||
|
return fingerprints
|
||||||
|
|
||||||
|
|
||||||
|
def get_fingerprints(working_dir: Path, input_path: Path, decomposed_paths: List[Path]) -> Set[str]:
|
||||||
|
"""Get the fingerprints of PGP public keys from input paths and decomposed directory structures
|
||||||
|
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
working_dir: Path
|
||||||
|
A directory to use for temporary files
|
||||||
|
input_path: Path
|
||||||
|
The path to a source file or directory
|
||||||
|
decomposed_paths: List[Path]
|
||||||
|
A list of paths that identify decomposed PGP data in directory structures
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Set[str]
|
||||||
|
A set of strings describing fingerprints of PGP public keys
|
||||||
|
"""
|
||||||
|
|
||||||
|
fingerprints: Set[str] = set()
|
||||||
|
|
||||||
|
fingerprints.update(
|
||||||
|
get_fingerprints_from_import_source(
|
||||||
|
working_dir=working_dir,
|
||||||
|
source=args.source,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for decomposed_path in decomposed_paths:
|
||||||
|
fingerprints.update(get_fingerprints_from_decomposed_dir(path=decomposed_path))
|
||||||
|
|
||||||
|
return fingerprints
|
||||||
|
|
||||||
|
|
||||||
def export_keyring(
|
def export_keyring(
|
||||||
working_dir: Path,
|
working_dir: Path,
|
||||||
main: List[Path],
|
main: List[Path],
|
||||||
@ -1155,6 +1255,11 @@ if __name__ == "__main__":
|
|||||||
source=args.source,
|
source=args.source,
|
||||||
target_dir=keyring_root / "main",
|
target_dir=keyring_root / "main",
|
||||||
name_override=args.name,
|
name_override=args.name,
|
||||||
|
fingerprint_filter=get_fingerprints(
|
||||||
|
working_dir=working_dir,
|
||||||
|
input_path=args.source,
|
||||||
|
decomposed_paths=[keyring_root / "main", keyring_root / "packagers"],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif "import-packager" == args.subcommand:
|
elif "import-packager" == args.subcommand:
|
||||||
@ -1164,6 +1269,11 @@ if __name__ == "__main__":
|
|||||||
source=args.source,
|
source=args.source,
|
||||||
target_dir=keyring_root / "packagers",
|
target_dir=keyring_root / "packagers",
|
||||||
name_override=args.name,
|
name_override=args.name,
|
||||||
|
fingerprint_filter=get_fingerprints(
|
||||||
|
working_dir=working_dir,
|
||||||
|
input_path=args.source,
|
||||||
|
decomposed_paths=[keyring_root / "main", keyring_root / "packagers"],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif "export-keyring" == args.subcommand:
|
elif "export-keyring" == args.subcommand:
|
||||||
|
Loading…
Reference in New Issue
Block a user