changeset 235:11819361ea39

Implement option "-e" for genpwd to require a binary length instead of the output length. This is effectively a minimum length.
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 07 Feb 2025 19:32:45 +0100
parents c7dc57c44e8b
children 939a8da6bc92
files cutils/genpwd.py
diffstat 1 files changed, 22 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/cutils/genpwd.py	Fri Feb 07 13:43:14 2025 +0100
+++ b/cutils/genpwd.py	Fri Feb 07 19:32:45 2025 +0100
@@ -41,15 +41,19 @@
                     " length within a character repertoire",
         fromfile_prefix_chars='@')
     aparser.add_argument(
+        "--version", "-v", action="version",
+        version="%s (rv:%s)" % (__version__, __revision__))
+    aparser.add_argument(
+        "-e", dest="use_bin_length", action="store_true",
+        help="For some repertoires make OUTPUT-LENGTH the number of bytes"
+             " that is to be read from random sources instead of output bytes")
+    aparser.add_argument(
         "--repertoire", "--type", "-t",
         choices=("web", "web-safe", "web-safe2",
                  "base64", "urlsafe-base64", "urlsafe", "base32", "ascii85", ),
         default="web-safe2",
         help="Select the character repertoire. Default: web-safe2")
     aparser.add_argument(
-        "--version", "-v", action="version",
-        version="%s (rv:%s)" % (__version__, __revision__))
-    aparser.add_argument(
         "req_length", metavar="OUTPUT-LENGTH", type=int,
         help="The required length of the generated password")
 
@@ -63,20 +67,28 @@
         pwd = gen_web(opts.req_length, WEB_SAFE2_CHARS)
     elif opts.repertoire == "base64":
         encoder = base64.b64encode
-        pwd = gen_bin(opts.req_length, encoder)
+        pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder,
+                      rstrip_chars=b"=")
     elif opts.repertoire in ("urlsafe-base64", "urlsafe"):
         encoder = base64.urlsafe_b64encode
-        pwd = gen_bin(opts.req_length, encoder)        
+        pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder,
+                      rstrip_chars=b"=")
     elif opts.repertoire == "base32":
         encoder = base64.b32encode
-        pwd = gen_bin(opts.req_length, encoder)
+        pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder,
+                      rstrip_chars=b"=")
     elif opts.repertoire == "ascii85":
         encoder = base64.a85encode
-        pwd = gen_bin(opts.req_length, encoder)
+        pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder)
     else:
         raise NotImplementedError("type not yet implemented: %s"
                                   % opts.repertoire)
-    assert len(pwd) == opts.req_length
+    if opts.use_bin_length:
+        if len(pwd) < opts.req_length:
+            raise AssertionError("internal length mismatch")
+    else:
+        if len(pwd) != opts.req_length:
+            raise AssertionError("internal length mismatch")
     if not PY2:
         pwd = pwd.decode("ascii")
     print(pwd)
@@ -102,9 +114,9 @@
     return pwd
 
 
-def gen_bin(length, encoder):
+def gen_bin(length, use_bin_length, encoder, rstrip_chars=None):
     pwd = encoder(os.urandom(length))
-    return pwd[:length]
+    return pwd.rstrip(rstrip_chars) if use_bin_length else pwd[:length]
 
 
 if __name__ == "__main__":