Mercurial > hgrepos > Python > apps > py-cutils
comparison cutils/genpwd.py @ 254:655f9e4bc6f2
genpwd: allow grouping of the output
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Thu, 13 Feb 2025 11:57:32 +0100 |
| parents | 4314ee20927a |
| children | 48430941c18c |
comparison
equal
deleted
inserted
replaced
| 253:4314ee20927a | 254:655f9e4bc6f2 |
|---|---|
| 99 aparser.add_argument( | 99 aparser.add_argument( |
| 100 "-E", dest="use_bin_length", action="store_true", | 100 "-E", dest="use_bin_length", action="store_true", |
| 101 help="For some repertoires make OUTPUT-LENGTH the number of bytes" | 101 help="For some repertoires make OUTPUT-LENGTH the number of bytes" |
| 102 " that is to be read from random sources instead of output bytes") | 102 " that is to be read from random sources instead of output bytes") |
| 103 aparser.add_argument( | 103 aparser.add_argument( |
| 104 "--group", "-G", action="store_true", | |
| 105 help="""Group the results. If no "--group-sep" or "--group-size" is | |
| 106 given use their respective defaults.""") | |
| 107 aparser.add_argument( | |
| 108 "--group-sep", action="store", default=None, metavar="GROUP-SEP", | |
| 109 help="""Group the result using GROUP-SEP as separator. | |
| 110 Option "--group" is implied. | |
| 111 Default when grouping is enabled is the SPACE character ` '.""") | |
| 112 aparser.add_argument( | |
| 113 "--group-size", action="store", type=int, default=None, | |
| 114 metavar="GROUP-SIZE", | |
| 115 help="""Group the result using a group size of GROUP-SIZE characters. | |
| 116 Option "--group" is implied. | |
| 117 Default when grouping is enabled is 6.""") | |
| 118 aparser.add_argument( | |
| 104 "req_length", metavar="OUTPUT-LENGTH", type=int, | 119 "req_length", metavar="OUTPUT-LENGTH", type=int, |
| 105 help="The required length of the generated output") | 120 help="The required length of the generated output") |
| 106 | 121 |
| 107 opts = aparser.parse_args(args=argv) | 122 opts = aparser.parse_args(args=argv) |
| 123 | |
| 124 grouper = None | |
| 125 if opts.group or opts.group_sep is not None or opts.group_size is not None: | |
| 126 if opts.group_sep is None: | |
| 127 gsep = b' ' | |
| 128 else: | |
| 129 if PY2: | |
| 130 gsep = opts.group_sep | |
| 131 else: | |
| 132 gsep = opts.group_sep.encode("utf8") | |
| 133 gsize = 6 if opts.group_size is None else opts.group_size | |
| 134 grouper = make_grouper(sep=gsep, size=gsize) | |
| 108 | 135 |
| 109 if opts.repertoire: | 136 if opts.repertoire: |
| 110 try: | 137 try: |
| 111 repertoire = (opts.repertoire | 138 repertoire = (opts.repertoire |
| 112 if PY2 | 139 if PY2 |
| 113 else opts.repertoire.encode("iso-8859-15")) | 140 else opts.repertoire.encode("iso-8859-15")) |
| 114 except UnicodeError: | 141 except UnicodeError: |
| 115 raise ValueError("non ISO-8859-15 character in given repertoire") | 142 raise ValueError("non ISO-8859-15 character in given repertoire") |
| 116 pwd = gen_from_repertoire(opts.req_length, repertoire) | 143 pwd = gen_from_repertoire(opts.req_length, repertoire, grouper=grouper) |
| 117 elif opts.algorithm == "web": | 144 elif opts.algorithm == "web": |
| 118 pwd = gen_from_repertoire(opts.req_length, WEB_CHARS) | 145 pwd = gen_from_repertoire( |
| 146 opts.req_length, WEB_CHARS, grouper=grouper) | |
| 119 elif opts.algorithm == "safe-web": | 147 elif opts.algorithm == "safe-web": |
| 120 pwd = gen_from_repertoire(opts.req_length, SAFE_WEB_CHARS) | 148 pwd = gen_from_repertoire( |
| 149 opts.req_length, SAFE_WEB_CHARS, grouper=grouper) | |
| 121 elif opts.algorithm == "safe-web-2": | 150 elif opts.algorithm == "safe-web-2": |
| 122 pwd = gen_from_repertoire(opts.req_length, SAFE_WEB_CHARS_2) | 151 pwd = gen_from_repertoire( |
| 152 opts.req_length, SAFE_WEB_CHARS_2, grouper=grouper) | |
| 123 elif opts.algorithm == "uri": | 153 elif opts.algorithm == "uri": |
| 124 pwd = gen_from_repertoire(opts.req_length, URI_CHARS) | 154 pwd = gen_from_repertoire( |
| 155 opts.req_length, URI_CHARS, grouper=grouper) | |
| 125 elif opts.algorithm == "safe-uri": | 156 elif opts.algorithm == "safe-uri": |
| 126 pwd = gen_from_repertoire(opts.req_length, SAFE_URI_CHARS) | 157 pwd = gen_from_repertoire( |
| 158 opts.req_length, SAFE_URI_CHARS, grouper=grouper) | |
| 127 elif opts.algorithm == "safe-uri-2": | 159 elif opts.algorithm == "safe-uri-2": |
| 128 pwd = gen_from_repertoire(opts.req_length, SAFE_URI_CHARS_2) | 160 pwd = gen_from_repertoire( |
| 161 opts.req_length, SAFE_URI_CHARS_2, grouper=grouper) | |
| 129 elif opts.algorithm == "ascii": | 162 elif opts.algorithm == "ascii": |
| 130 pwd = gen_from_repertoire(opts.req_length, FULL_ASCII) | 163 pwd = gen_from_repertoire( |
| 164 opts.req_length, FULL_ASCII, grouper=grouper) | |
| 131 elif opts.algorithm == "safe-ascii": | 165 elif opts.algorithm == "safe-ascii": |
| 132 pwd = gen_from_repertoire(opts.req_length, SAFE_ASCII) | 166 pwd = gen_from_repertoire( |
| 167 opts.req_length, SAFE_ASCII, grouper=grouper) | |
| 133 elif opts.algorithm == "alnum": | 168 elif opts.algorithm == "alnum": |
| 134 pwd = gen_from_repertoire(opts.req_length, ALNUM) | 169 pwd = gen_from_repertoire(opts.req_length, ALNUM, grouper=grouper) |
| 135 elif opts.algorithm == "safe-alnum": | 170 elif opts.algorithm == "safe-alnum": |
| 136 pwd = gen_from_repertoire(opts.req_length, SAFE_ALNUM) | 171 pwd = gen_from_repertoire( |
| 172 opts.req_length, SAFE_ALNUM, grouper=grouper) | |
| 137 elif opts.algorithm == "bin-base64": | 173 elif opts.algorithm == "bin-base64": |
| 138 encoder = base64.b64encode | 174 encoder = base64.b64encode |
| 139 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, | 175 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, |
| 140 rstrip_chars=b"=") | 176 rstrip_chars=b"=", grouper=grouper) |
| 141 elif opts.algorithm == "bin-urlsafe-base64": | 177 elif opts.algorithm == "bin-urlsafe-base64": |
| 142 encoder = base64.urlsafe_b64encode | 178 encoder = base64.urlsafe_b64encode |
| 143 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, | 179 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, |
| 144 rstrip_chars=b"=") | 180 rstrip_chars=b"=", grouper=grouper) |
| 145 elif opts.algorithm == "bin-base32": | 181 elif opts.algorithm == "bin-base32": |
| 146 encoder = base64.b32encode | 182 encoder = base64.b32encode |
| 147 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, | 183 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder, |
| 148 rstrip_chars=b"=") | 184 rstrip_chars=b"=", grouper=grouper) |
| 149 elif opts.algorithm == "bin-ascii85": | 185 elif opts.algorithm == "bin-ascii85": |
| 150 encoder = base64.a85encode | 186 encoder = base64.a85encode |
| 151 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder) | 187 pwd = gen_bin( |
| 188 opts.req_length, opts.use_bin_length, encoder, grouper=grouper) | |
| 152 elif opts.algorithm == "bin-hex": | 189 elif opts.algorithm == "bin-hex": |
| 153 encoder = binascii.hexlify | 190 encoder = binascii.hexlify |
| 154 pwd = gen_bin(opts.req_length, opts.use_bin_length, encoder) | 191 pwd = gen_bin( |
| 192 opts.req_length, opts.use_bin_length, encoder, grouper=grouper) | |
| 155 else: | 193 else: |
| 156 raise NotImplementedError("algorithm not yet implemented: %s" | 194 raise NotImplementedError("algorithm not yet implemented: %s" |
| 157 % opts.algorithm) | 195 % opts.algorithm) |
| 158 if opts.use_bin_length: | 196 if opts.group or opts.group_size or opts.group_sep: |
| 159 if len(pwd) < opts.req_length: | 197 if len(pwd) < opts.req_length: |
| 160 raise AssertionError("internal length mismatch") | 198 raise AssertionError("internal length mismatch") |
| 161 else: | 199 else: |
| 162 if len(pwd) != opts.req_length: | 200 if opts.use_bin_length: |
| 163 raise AssertionError("internal length mismatch") | 201 if len(pwd) < opts.req_length: |
| 202 raise AssertionError("internal length mismatch") | |
| 203 else: | |
| 204 if len(pwd) != opts.req_length: | |
| 205 raise AssertionError("internal length mismatch") | |
| 164 if PY2: | 206 if PY2: |
| 165 print(pwd) | 207 print(pwd) |
| 166 sys.stdout.flush() | 208 sys.stdout.flush() |
| 167 else: | 209 else: |
| 168 sys.stdout.buffer.write(pwd) | 210 sys.stdout.buffer.write(pwd) |
| 169 sys.stdout.buffer.write(b'\n') | 211 sys.stdout.buffer.write(b'\n') |
| 170 sys.stdout.buffer.flush() | 212 sys.stdout.buffer.flush() |
| 171 | 213 |
| 172 | 214 |
| 173 def gen_from_repertoire(length, repertoire): | 215 def gen_from_repertoire(length, repertoire, grouper=None): |
| 174 """Select `length` characters randomly from given character repertoire | 216 """Select `length` characters randomly from given character repertoire |
| 175 `repertoire`. | 217 `repertoire`. |
| 176 | 218 |
| 177 """ | 219 """ |
| 178 assert len(repertoire) <= 256 | 220 assert len(repertoire) <= 256 |
| 188 break | 230 break |
| 189 if PY2: | 231 if PY2: |
| 190 pwd = b''.join(pwd) | 232 pwd = b''.join(pwd) |
| 191 else: | 233 else: |
| 192 pwd = bytes(pwd) | 234 pwd = bytes(pwd) |
| 235 if grouper: | |
| 236 pwd = grouper(pwd) | |
| 193 return pwd | 237 return pwd |
| 194 | 238 |
| 195 | 239 |
| 196 def gen_bin(length, use_bin_length, encoder, rstrip_chars=None): | 240 def gen_bin(length, use_bin_length, encoder, rstrip_chars=None, grouper=None): |
| 197 """Generate from :func:`os.urandom` and just encode with given `encoder`. | 241 """Generate from :func:`os.urandom` and just encode with given `encoder`. |
| 198 | 242 |
| 199 """ | 243 """ |
| 200 pwd = encoder(os.urandom(length)) | 244 pwd = encoder(os.urandom(length)) |
| 201 return pwd.rstrip(rstrip_chars) if use_bin_length else pwd[:length] | 245 pwd = pwd.rstrip(rstrip_chars) if use_bin_length else pwd[:length] |
| 246 if grouper: | |
| 247 pwd = grouper(pwd) | |
| 248 return pwd | |
| 249 | |
| 250 | |
| 251 def make_grouper(sep=b' ', size=6): | |
| 252 | |
| 253 def _grouper(pwd): | |
| 254 if not pwd or size <= 0: | |
| 255 return pwd | |
| 256 assert isinstance(pwd, bytes) | |
| 257 groups = [] | |
| 258 idx = 0 | |
| 259 while idx < len(pwd): | |
| 260 groups.append(pwd[idx:idx+size]) | |
| 261 idx += size | |
| 262 return sep.join(groups) | |
| 263 | |
| 264 assert isinstance(sep, bytes) | |
| 265 return _grouper | |
| 202 | 266 |
| 203 | 267 |
| 204 if __name__ == "__main__": | 268 if __name__ == "__main__": |
| 205 main() | 269 main() |
