ldaptool-0.6
-----BEGIN PGP SIGNATURE----- iQJYBAABCgBCFiEEcdms641aWv8vJSXMIcx4mUG+20gFAmRdCeokHHN0ZWZhbi5i dWVobGVyQHRpay51bmktc3R1dHRnYXJ0LmRlAAoJECHMeJlBvttI1UgP/25ZthYC I063KZ+r/ZjF2JpF8sWBRNpnL6spP2NyeTOF9SxGW/caD/Cc0wIVpweBVynevCx3 vo7x0WS0jcIDKZ7eUwvzM+bN6qdoxlb3Z1SHnz/eDcg8qTHgroZ3e77UGm6hlHkh mOWcj2+fJ0PXdb0+gxnF8djeqATioq9Ijql/QpGg4FR7fo5uZhXbefa+n1h5qFDp a9KCn9E1hyoZWFv/5z33dhooFkS78jRtUco+ZDsuav9N6zRqKH78MXxv3NpynnIT dCXzSBST3v/Ki5G64aU0fDQctqE3j5oEAnasoVTp/yRwJfIWnaFf6reN/CzCC7C3 8/N4vDEQ8+aOtRt61R48tvAwgzqtW4hppLyv55DdU4Y4HFOm5E39bnPUqQ2VDwww 56lQPZ1xTiPnunUIYfw9qTBMOjb2DyW3Blx7Q2Rm63rVhLZac0b6E8iwpIkyMWy8 8pGm7O8a754QSKpngBy55rWZMuBmBh3wPI29txaZyvCSqiLA7xIdf82DXQqOyLRs fMwy/U3Si+HeWuD7ON/D3rWn7OaWHKh6WR2FY8NWUT/aIyZSMVtRp6k+WqIeoxH0 KExJ8YEQ6XGNUhInWF8//gWvjbLXIEs8sCFim4KClFA8ejAWehbB0eF0gCuar3tA b8XdMOGoxPcymvI+h/ivroQLWO297DJQ28BM =Spnc -----END PGP SIGNATURE----- Merge tag 'ldaptool-0.6' into debian ldaptool-0.6
This commit is contained in:
commit
ba6cc242f1
@ -9,7 +9,7 @@ CLI tool to query LDAP/AD servers
|
||||
* Integration with password managers
|
||||
* Various output formats
|
||||
* Classic LDIF
|
||||
* JSON stream (with detailed or simplified attribute values)
|
||||
* JSON stream (with simplified or detailed attribute values)
|
||||
* CSV
|
||||
* Markdown table with stretched columns (for viewing in CLI/for monospaces fonts); requires csvlook from [csvkit](https://csvkit.readthedocs.io/)
|
||||
* HTML
|
||||
|
@ -55,13 +55,17 @@ class Arguments(search.Arguments):
|
||||
help="Sorted table output - defaults to markdown --table unless --csv is given",
|
||||
),
|
||||
)
|
||||
full_json: bool = dataclasses.field(
|
||||
default=False,
|
||||
metadata=argclasses.arg(
|
||||
help="Use full json output (dn as str, attributes as list of dicts containing various represenatations)",
|
||||
),
|
||||
)
|
||||
json: bool = dataclasses.field(
|
||||
default=False,
|
||||
metadata=argclasses.arg(help="Use full json output"),
|
||||
)
|
||||
human: bool = dataclasses.field(
|
||||
default=False,
|
||||
metadata=argclasses.arg(help="Use simple json output (join multiple values of one attribute)"),
|
||||
metadata=argclasses.arg(
|
||||
help="Use simple json output (dn as str, attributes map to list of human-readable strings)",
|
||||
),
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
@ -85,15 +89,15 @@ class Arguments(search.Arguments):
|
||||
if self.table_output:
|
||||
if not self.columns:
|
||||
raise SystemExit("Table output requires attributes")
|
||||
if self.json:
|
||||
if self.full_json:
|
||||
raise SystemExit("Can't use both table output and --json")
|
||||
if self.human:
|
||||
if self.json:
|
||||
raise SystemExit("Can't use both table output and --human")
|
||||
|
||||
if self.raw:
|
||||
if self.table_output:
|
||||
raise SystemExit("Table output requires decode; --raw not allowed")
|
||||
if self.json or self.human:
|
||||
if self.full_json or self.json:
|
||||
raise SystemExit("Decode options require decode; --raw not allowed")
|
||||
|
||||
|
||||
@ -183,7 +187,7 @@ class _Context:
|
||||
num_responses = 0
|
||||
num_entries = 0
|
||||
|
||||
ldif_output = not (self.arguments.json or self.arguments.human)
|
||||
ldif_output = not (self.arguments.full_json or self.arguments.json)
|
||||
|
||||
if ldif_output:
|
||||
print("# extended LDIF")
|
||||
@ -214,11 +218,11 @@ class _Context:
|
||||
num_entries += 1
|
||||
if ldif_output:
|
||||
decoder.read_and_emit_ldif(dn=dn, entry=entry, file=stream)
|
||||
elif self.arguments.human:
|
||||
decoder.read_and_emit_human(dn=dn, entry=entry, file=stream)
|
||||
elif self.arguments.json:
|
||||
decoder.read_and_emit_simple_json(dn=dn, entry=entry, file=stream)
|
||||
else:
|
||||
assert self.arguments.json
|
||||
decoder.read_and_emit_json(dn=dn, entry=entry, file=stream)
|
||||
assert self.arguments.full_json
|
||||
decoder.read_and_emit_full_json(dn=dn, entry=entry, file=stream)
|
||||
except SizeLimitExceeded as e:
|
||||
raise SystemExit(f"Error: {e}")
|
||||
|
||||
|
@ -101,7 +101,7 @@ class Attribute:
|
||||
return
|
||||
|
||||
def _try_decode(self, args: Arguments) -> None:
|
||||
if self.name in ("objectSid","securityIdentifier"):
|
||||
if self.name in ("objectSid", "securityIdentifier"):
|
||||
self._try_decode_sid()
|
||||
elif self.name in ("msExchMailboxGuid", "objectGUID"):
|
||||
self._try_decode_uuid()
|
||||
@ -192,30 +192,30 @@ class Decoder:
|
||||
def human(self, *, dn: str, obj: TDecoded) -> dict[str, str]:
|
||||
emit: dict[str, typing.Any] = dict(dn=dn)
|
||||
for name, attrs in obj.items():
|
||||
emit[name] = self.arguments.human_separator.join(attr.human() for attr in attrs)
|
||||
emit[name] = [attr.human() for attr in attrs]
|
||||
return emit
|
||||
|
||||
def emit_human(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None:
|
||||
def emit_simple_json(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None:
|
||||
emit = self.human(dn=dn, obj=obj)
|
||||
json.dump(emit, file, ensure_ascii=False)
|
||||
print(file=file) # terminate output dicts by newline
|
||||
|
||||
def read_and_emit_human(self, *, dn: str, entry: TEntry, file: typing.IO[str] = sys.stdout) -> None:
|
||||
self.emit_human(dn=dn, obj=self.read(dn=dn, entry=entry), file=file)
|
||||
def read_and_emit_simple_json(self, *, dn: str, entry: TEntry, file: typing.IO[str] = sys.stdout) -> None:
|
||||
self.emit_simple_json(dn=dn, obj=self.read(dn=dn, entry=entry), file=file)
|
||||
|
||||
def json(self, *, dn: str, obj: TDecoded) -> dict[str, str]:
|
||||
def full_json(self, *, dn: str, obj: TDecoded) -> dict[str, str]:
|
||||
emit: dict[str, typing.Any] = dict(dn=dn)
|
||||
for name, attrs in obj.items():
|
||||
emit[name] = [attr.to_json() for attr in attrs]
|
||||
return emit
|
||||
|
||||
def emit_json(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None:
|
||||
emit = self.json(dn=dn, obj=obj)
|
||||
def emit_full_json(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None:
|
||||
emit = self.full_json(dn=dn, obj=obj)
|
||||
json.dump(emit, file, ensure_ascii=False)
|
||||
print(file=file) # terminate output dicts by newline
|
||||
|
||||
def read_and_emit_json(self, *, dn: str, entry: TEntry, file: typing.IO[str] = sys.stdout) -> None:
|
||||
self.emit_json(dn=dn, obj=self.read(dn=dn, entry=entry), file=file)
|
||||
def read_and_emit_full_json(self, *, dn: str, entry: TEntry, file: typing.IO[str] = sys.stdout) -> None:
|
||||
self.emit_full_json(dn=dn, obj=self.read(dn=dn, entry=entry), file=file)
|
||||
|
||||
def emit_ldif(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None:
|
||||
print(f"dn: {dn}", file=file)
|
||||
|
Loading…
Reference in New Issue
Block a user