Coverage for python/univention/ldif.py: 74%

60 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2026-09-11 14:11 +0000

1#!/usr/bin/python3 

2# SPDX-FileCopyrightText: 2004-2026 Univention GmbH 

3# SPDX-License-Identifier: AGPL-3.0-only 

4 

5"""Univention LDIF tool""" 

6 

7 

8import re 

9import sys 

10from argparse import ArgumentParser 

11from base64 import b64decode 

12from collections.abc import Iterable, Iterator 

13from typing import IO 

14 

15 

16__all__ = [ 

17 "ldif_decode", 

18 "ldif_normalize", 

19 "ldif_unwrap", 

20] 

21 

22RE_B64 = re.compile(r'^([a-zA-Z0-9-]+):: (.*)') 

23 

24 

25def ldif_decode(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None: 

26 """Decode bas64 in LDIF.""" 

27 try: 

28 for line in src: 

29 dst.write(decode64(line)) 

30 except BrokenPipeError: 

31 pass 

32 

33 

34def decode(stream: Iterable[str]) -> Iterator[bytes]: 

35 for line in stream: 

36 yield decode64(line) 

37 

38 

39def decode64(line: str) -> bytes: 

40 m = RE_B64.search(line) 

41 if m: 

42 attr, encoded = m.groups() 

43 decoded = b64decode(encoded) 

44 return b"%s: %s\n" % (attr.encode("utf-8"), decoded) 

45 else: 

46 return line.encode("utf-8") 

47 

48 

49def ldif_unwrap(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None: 

50 """Unwrap LDIF.""" 

51 try: 

52 for line in unwrap(src): 

53 dst.write(line.encode("utf-8")) 

54 except BrokenPipeError: 

55 pass 

56 

57 

58def unwrap(stream: Iterable[str]) -> Iterator[str]: 

59 prev = "" 

60 for line in stream: 

61 if line[:1] in (' ', '\t'): 

62 prev = prev.rstrip("\n\r") + line[1:] 

63 else: 

64 if prev: 

65 yield prev 

66 prev = line 

67 

68 if prev: 68 ↛ exitline 68 didn't return from function 'unwrap' because the condition on line 68 was always true

69 yield prev 

70 

71 

72def ldif_normalize(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None: 

73 """Unwrap and base64 decode LDIF.""" 

74 try: 

75 for line in unwrap(src): 

76 dst.write(decode64(line)) 

77 except BrokenPipeError: 

78 pass 

79 

80 

81def main() -> None: 

82 parser = ArgumentParser(description=__doc__) 

83 parser.add_argument("--src", "-s", default="-", help="Source input") 

84 parser.add_argument("--dst", "-d", default="-", help="Destination output") 

85 

86 parser.set_defaults(func=ldif_normalize) 

87 subparsers = parser.add_subparsers(help="Sub-command help") 

88 

89 parser_decode = subparsers.add_parser("decode", help=ldif_decode.__doc__) 

90 parser_decode.set_defaults(func=ldif_decode) 

91 

92 parser_unwrap = subparsers.add_parser("unwrap", help=ldif_unwrap.__doc__) 

93 parser_unwrap.set_defaults(func=ldif_unwrap) 

94 

95 args = parser.parse_args() 

96 src = sys.stdin if args.src == "-" else open(args.src) 

97 dst = sys.stdout if args.dst == "-" else open(args.dst, "w") 

98 args.func(src, dst.buffer) 

99 

100 

101if __name__ == "__main__": 

102 main()