I'm new to python and trying to figure out how to make this code accept multiple of the same argument -ex. I tried make it a action='append' but that gives me a error saying it need to be a string not a list. right now when using -ex several times it just uses the last instance of it
example. python3 scrunch.py --no-rep -ex 123 -ex 456 5 5 abcdefg123456
output 12345
the output still contains 123.
import string
import argparse
import itertools
from math import factorial
def number_permutations(n, k):
return factorial(n)/factorial(n-k)
def main():
parser = argparse.ArgumentParser(description='Generate password combinations from charset'
'with length in range: [MIN..MAX]. '
'If any of -u, -l, -d, -hex option is set, then charset is ignored, but still must be provided.')
parser = argparse.ArgumentParser(epilog="Example 1: "
'python3 scrunch.py --no-rep -ex ABC 3 5 ABCDEFGH123456 '
'Example 2: '
'python3 scrunch.py --no-rep -f wordlist.txt -u -l -d 6 6 DUMMYCHARSET')
parser.add_argument('-f', metavar='file', help='output text file name. Prints to STDOUT by default')
parser.add_argument('-u', action='store_true', help='Use all uppercase characters. Overrides charset')
parser.add_argument('-l', action='store_true', help='Use all lowercase characters. Overrides charset')
parser.add_argument('-d', action='store_true', help='Use all decimal numbers. Overrides charset')
parser.add_argument('-hex', action='store_true', help='Use all hex numbers. Overrides charset')
parser.add_argument('-ex', help='Exclude char sequence')
parser.add_argument('--no-digit-start', action='store_true', help='Do not start with digit')
parser.add_argument('minlen', metavar='MIN', type=int,
help='Min length of combination')
parser.add_argument('maxlen', metavar='MAX', type=int,
help='Max length of combination')
parser.add_argument('charset', nargs=1)
parser.add_argument('--no-rep', action='store_true', help='Any symbol can occur only once.')
args = parser.parse_args()
print (args.ex)
a = ''.join(args.charset)
b = ''
if args.u:
b += string.ascii_uppercase
if args.l:
b += string.ascii_lowercase
if args.hex:
b += string.hexdigits
if args.d:
b += string.digits
if b:
a = b
s = sorted(a)
print ("Sorted charset: {}".format(s))
num = 0
# Calculate number of possible combinations
for L in range(args.minlen, args.maxlen + 1):
num += number_permutations(len(s), L)
print ("Number of permutations: %d" % num)
if args.f:
f = open(args.f, 'w')
for L in range(args.minlen, args.maxlen + 1):
if args.no_digit_start and args.no_rep:
gen = permutations_no_digit_start(s, L)
elif args.no_rep:
gen = itertools.permutations(s, L)
else:
gen = itertools.product(s, repeat=L)
for x in gen:
y = ''.join(x)
if args.ex and args.ex in y:
continue
if args.no_digit_start and y[0].isdigit():
continue
if args.f:
f.write("%s\n" % ''.join(x))
else:
print (''.join(x))
main()
replace line
parser.add_argument('-ex', help='Exclude char sequence')
to
parser.add_argument('-ex', action='append', help='Exclude char sequence')
replace if
check
if args.ex and args.ex in y:
continue
to
bad_pattern = False
for ex in args.ex:
if ex and ex in y:
bad_pattern = True
break
if bad_pattern:
continue
Explanation: by default only last value of -ex
used. And that is 456
. But action='append'
allows to set list of values. And every usage of -ex
will append new value to list. After that you have to check every value in args.ex
list by iterating for ex in args.ex