From 26c7027660160b63459c7b48e638d3e4577d0793 Mon Sep 17 00:00:00 2001 From: Levente Polyak Date: Tue, 26 Oct 2021 19:24:30 +0200 Subject: [PATCH] feature(keyringctl): support importing from a piped fd This feature allows to import from a piped fd like: > ./keyringctl import --name foobar <(gpg --export foo@bar) We achieve this even with hidepid by taking the naive approach of copying the processes fd source to a tempfile and pass around latter. --- libkeyringctl/cli.py | 4 ++-- libkeyringctl/keyring.py | 10 ++++++---- libkeyringctl/util.py | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libkeyringctl/cli.py b/libkeyringctl/cli.py index 91cf890..cec29c3 100644 --- a/libkeyringctl/cli.py +++ b/libkeyringctl/cli.py @@ -140,7 +140,7 @@ def main() -> None: # noqa: ignore=C901 convert( working_dir=working_dir, keyring_root=keyring_root, - source=args.source, + sources=args.source, target_dir=target_dir, name_override=args.name, ) @@ -151,7 +151,7 @@ def main() -> None: # noqa: ignore=C901 convert( working_dir=working_dir, keyring_root=keyring_root, - source=args.source, + sources=args.source, target_dir=keyring_root / target_dir, name_override=args.name, ) diff --git a/libkeyringctl/keyring.py b/libkeyringctl/keyring.py index 329a2f1..a381379 100644 --- a/libkeyringctl/keyring.py +++ b/libkeyringctl/keyring.py @@ -30,6 +30,7 @@ from .types import Fingerprint from .types import Uid from .types import Username from .util import system +from .util import transform_fd_to_tmpfile def is_pgp_fingerprint(string: str) -> bool: @@ -578,7 +579,7 @@ def derive_username_from_fingerprint(keyring_dir: Path, certificate_fingerprint: def convert( working_dir: Path, keyring_root: Path, - source: Iterable[Path], + sources: List[Path], target_dir: Path, name_override: Optional[Username] = None, ) -> Path: @@ -590,7 +591,7 @@ def convert( ---------- working_dir: A directory to use for temporary files keyring_root: The keyring root directory to look up accepted fingerprints for certifications - source: A path to a file or directory to decompose + sources: A path to a file or directory to decompose target_dir: A directory path to write the new directory structure to name_override: An optional username override for the call to `convert_certificate()` @@ -600,12 +601,13 @@ def convert( """ directories: List[Path] = [] - keys: Iterable[Path] = set(chain.from_iterable(map(lambda s: s.iterdir() if s.is_dir() else [s], source))) + transform_fd_to_tmpfile(working_dir=working_dir, sources=sources) + keys: Iterable[Path] = set(chain.from_iterable(map(lambda s: s.iterdir() if s.is_dir() else [s], sources))) fingerprint_filter = set( get_fingerprints( working_dir=working_dir, - sources=source, + sources=sources, paths=[keyring_root] if keyring_root.exists() else [], ).keys() ) diff --git a/libkeyringctl/util.py b/libkeyringctl/util.py index 8c21b02..f8fa7a8 100644 --- a/libkeyringctl/util.py +++ b/libkeyringctl/util.py @@ -12,6 +12,7 @@ from subprocess import CalledProcessError from subprocess import check_output from sys import exit from sys import stderr +from tempfile import mkstemp from traceback import print_stack from typing import IO from typing import AnyStr @@ -121,3 +122,23 @@ def absolute_path(path: str) -> Path: """ return Path(path).absolute() + + +def transform_fd_to_tmpfile(working_dir: Path, sources: List[Path]) -> None: + """Transforms an input list of paths from any file descriptor of the current process to a tempfile in working_dir. + + Using this function on fd inputs allow to pass the content to another process while hidepid is active and /proc + not visible for the other process. + + Parameters + ---------- + working_dir: A directory to use for temporary files + sources: Paths that should be iterated and all fd's transformed to tmpfiles + """ + for index, source in enumerate(sources): + if str(source).startswith("/proc/self/fd"): + file = mkstemp(dir=working_dir, prefix=f"{source.name}", suffix=".fd")[1] + with open(file, mode="wb") as f: + f.write(source.read_bytes()) + f.flush() + sources[index] = Path(file)