view cutils/genpwd.py @ 230:ccbb6905914e

Change copyright and note genpwd in the READNE and make an official script
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 07 Feb 2025 12:58:55 +0100
parents 788f14425503
children 6d8443878a00
line wrap: on
line source

# -*- coding: utf-8 -*-
# :-
# :Copyright: (c) 2018 Franz Glasner
# :Copyright: (c) 2025 Franz Glasner
# :License:   BSD-3-Clause
# :-
r"""Generate passwords.

Usage: genpwd.py [ Options ] required_length

Options:

  --type, -t    web, web-safe, web-safe2, base64, base32, ascii85

:Author:  Franz Glasner

"""

from __future__ import (division, absolute_import, print_function)

import getopt
import sys
import os
import base64

from . import (__version__, __revision__)


WEB_CHARS = b"ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwxyz0123456789.,-_;!()[]{}*"
WEB_SAFE_CHARS = b"ABCDEFGHJKLMNPQRSTUVWYXZabcdefghijkmnopqrstuvwxyz23456789.,-_;!"
WEB_SAFE2_CHARS = b".,-_;!" + WEB_SAFE_CHARS

PY2 = sys.version_info[0] <= 2


def main():
    opt_type = "web-safe2"
    opts, args = getopt.getopt(sys.argv[1:],
                               "t:",
                               ["type="])
    for opt, val in opts:
        if opt in ("-t", "--type"):
            if val not in ("web", "web-safe", "web-safe2",
                           "base64", "base32", "ascii85", ):
                raise getopt.GetoptError("invalid type: %s" % val, "")
            opt_type = val
        else:
            raise RuntimeError("inconsistent getopt handling")

    try:
        req_length = int(args[0], 10)
    except IndexError:
        raise getopt.GetoptError("no length given")

    if opt_type == "web":
        pwd = gen_web(req_length, WEB_CHARS)
    elif opt_type == "web-safe":
        pwd = gen_web(req_length, WEB_SAFE_CHARS)
    elif opt_type == "web-safe2":
        pwd = gen_web(req_length, WEB_SAFE2_CHARS)
    elif opt_type == "base64":
        encoder = base64.b64encode
        pwd = gen_bin(req_length, encoder)
    elif opt_type == "base32":
        encoder = base64.b32encode
        pwd = gen_bin(req_length, encoder)
    elif opt_type == "ascii85":
        encoder = base64.a85encode
        pwd = gen_bin(req_length, encoder)
    else:
        raise NotImplementedError("type not yet implemented: %s" % opt_type)
    print(pwd)


def gen_web(length, chars):
    mult = 256//len(chars)
    repertoire = chars * mult
    assert len(repertoire) <= 256
    pwd = []
    while len(pwd) < length:
        c = os.urandom(1)
        if PY2:
            c = ord(c)
        else:
            c = c[0]
        if c < len(repertoire):
            pwd.append(repertoire[c])
    if PY2:
        pwd = b''.join(pwd)
    else:
        pwd = bytes(pwd)
    return pwd


def gen_bin(length, encoder):
    pwd = encoder(os.urandom(length))
    return pwd[:length]


if __name__ == "__main__":
    main()