Quickly create large amounts of unique licenses. Heavily inspired by random code generator.
Making a batch of unique licenses is very simple. Run the script with:
python3 main.py
Let's go ahead and create 1000
licenses. We want the licenses to be 20
symbols long and we want to include numbers, uppercase letters, and lowercase
letters, but not symbols:
File Options
============
File extension (keep blank for txt):
Batch Options
=============
Number of licenses: 1000
License separator character (keep blank for newline):
License Characteristics Options
===============================
License length: 20
Enter 'y' to use numbers: y
Enter 'y' to use uppercase letters: y
Enter 'y' to use lowercase letters: y
Enter 'y' to use symbols: n
Results
=======
File path: /Users/josephlyons/Programming/Python/andromeda/src/1000_unique_licenses.txt
Requested number of licenses: 1000
Total possible number of licenses given current inputs: 62^20 = 704423425546998022968330264616370176
License pool coverage: (1000 / (62^20)) * 100 = 1.4196007170310687e-31%
When we are done, we will find a new file within the same folder as this script
named 1000_unique_licenses.txt
. Opening the file, we see:
dPzu8znblSPF1rmy4coW
djKD1ZxNLqAAo6ah6ZuA
dCZbvdHO9KIvm3CAnNCE
dzfN89poHQ7QMxZgGKH1
dqnj4G4A3mh23SpeoaZG
drsWemJsfg6aCzw0wHge
dYGS8jevEv5T0PFnd1bZ
dDSR4ZrQ2JgVZT2GmV4t
doO2eKULC3JLfuWBhQys
dp5yr9w1PrPpuAIWcGMH
dgFnW1Eppccc5gRNEFAR
dWosgmKFvdFtbKvCDB5X
dyTmrjnIhLK1pwhmXr9V
dMJQWVxqxRSjyt5lIOey
dwbPgKHTq5frkOzHJ0wP
dFheZibfSFeXVlPfzeSg
...
- Check to make sure that it is possible to create the amount of unique
licenses requested based on the the license length and character set. For
example, if the user requests
1,000,000
unique licenses, but only asks for licenses of length4
and wants only numbers as characters, it will not be possible, as10^4 < 1,000,000
. We must have more possible combinations than the number of licenses requested in order to ensure all licenses will be unique. - Make a
characterList
that is comprised of all the symbols the user wishes to use in their licenses (numbers, lowercase letters, uppercase letters, and symbols). - Shuffle this list and push a copy of it into another list, called
listOfCharacterLists
. This step is executed as many times as the length of the license requested. - Create a new list of numbers called
index_list
. Each cell in this list holds an index that corresponds to acharacterList
in thelistOfCharacterLists
. - A license is generated by using the
index_list
to provide an index to each of the corresponding internalcharacterList
s inlistOfCharacterLists
. ThelistOfCharacterLists
contains as many internalcharacterList
s as the length of our license. This can be seen sort of as a speedometer that starts with0000
miles. As we roll through the miles in the rightmost column, it resets back to zero and the next value to the left increments by1
. This is exactly how theindex_list
andlistOfCharacterLists
work to obtain licenses.
In order to avoid printing licenses that look like this:
PWZdySrxntWyBxYYZAlT
PWZdySrxntWyBxYYZAlB
PWZdySrxntWyBxYYZAlZ
PWZdySrxntWyBxYYZAlJ
...
we need to pull licenses evenly over the entire spectrum of possible
combinations. We can do this by taking the total possible combinations based on
the user settings and dividing it by the number of licenses needed. This will
give us the value that we need to be apply to the index_list
before printing
the next license to the file.
Using the example from earlier, our licenses are of length 20
and use 62
types of symbols (10
numbers + 26
lowercase letters + 26
uppercase
letters). We have 62^20
possible unique license combinations. Because we
want 1000
licenses, the spacing between licenses to be printed to the file is
(62^20) / 1000 = 7.04423425546998e+32
. If we set n = 7.04423425546998e+32
,
then the function increaseIndexVectorBy()
efficiently applies this number to
the index_list
in roughly log(n) with base 62
operations. Using this method,
we are able to print licenses that are equally spaced apart in the total
combination space, as shown in the first sample output earlier.
We can even print all of the values of the index_list
to the terminal to see
the patterns better by uncommenting print(self.index_list.get_index_string())
:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 03 52 20 20 51 36 12 55 34 13 55 03 29 16 22 50 36 43 40
00 07 42 40 41 41 10 25 49 06 27 48 06 58 32 45 39 11 25 18
00 11 32 61 00 30 46 38 42 40 41 41 10 25 49 06 27 48 06 58
00 15 23 19 21 20 20 51 36 12 55 34 13 55 03 29 16 22 50 36
00 19 13 39 42 09 57 02 29 47 07 27 17 22 19 52 04 59 32 14
00 23 03 60 00 61 31 15 23 19 21 20 20 51 36 12 55 34 13 54
00 26 56 18 21 51 05 28 16 53 35 13 24 18 52 35 44 08 57 32
00 30 46 38 42 40 41 41 10 25 49 06 27 48 06 58 32 45 39 10
00 34 36 59 01 30 15 54 03 60 00 61 31 15 23 19 21 20 20 50
00 38 27 17 22 19 52 04 59 32 14 54 34 44 39 42 09 57 02 28
00 42 17 37 43 09 26 17 53 04 28 47 38 11 56 02 60 31 46 06
00 46 07 58 01 61 00 30 46 38 42 40 41 41 10 25 49 06 27 46
00 49 60 16 22 50 36 43 40 10 56 33 45 08 26 48 37 43 09 24
00 53 50 36 43 40 10 56 33 45 08 26 48 37 43 09 26 17 53 02
00 57 40 57 02 29 47 07 27 17 22 19 52 04 59 32 14 54 34 42
...
Andromeda allows you to pick you own file extension and the license separator
character. This means you can build license files however you like. The
previous example demonstrates the creation of a .txt
file where the license
separation character is a newline, resulting in each license being on its own
line. You could also create a comma separated value file by specifying .csv
as the file extension and ,
as the license separator character. It should be
noted that if you choose a license separator character that is not a newline and
the license separator character also exists in the character list you allow for
generating licenses, it will be removed automatically from the character list;
you do not want a license separator character showing up randomly in the middle
of a license.
Andromeda does not care if you choose settings that result in a very low pool of license combinations for it to pick from. You should be aware of this. Consider the following example:
File Options
============
File extension (keep blank for txt):
Batch Options
=============
Number of licenses: 1000
License separator character (keep blank for newline):
License Characteristics Options
===============================
License length: 4
Enter 'y' to use numbers: y
Enter 'y' to use uppercase letters: n
Enter 'y' to use lowercase letters: n
Enter 'y' to use symbols: n
Results
=======
File path: /Users/josephlyons/Programming/Python/andromeda/src/1000_unique_licenses.txt
Requested number of licenses: 1000
Total possible number of licenses given current inputs: 10^4 = 10000
License pool coverage: (1000 / (10^4)) * 100 = 10.0%
The output file produced will look something like this:
9444
9474
9494
9464
9484
9434
9424
9404
9414
9454
9244
9274
9294
9264
9284
9234
...
Notice that the licenses are fairly similar. Also, note that it would be fairly
easy to randomly guess a license. The probability that a random guess would be
an actual license is 1000 / (10^4) = 0.1
. Andromeda tries to help the user by
calculating and printing out the license pool coverage:
License pool coverage: (1000 / (10^4)) * 100 = 10.0%
but it is ultimately up to the user to understand what this means and adjust the
settings to both increase the complexity of the output and decrease the chances
of guessing a license. Using the example from earlier with 1000
licenses of
length 20
using all symbols, the probability that a random guess would be an
actual license is 1000 / (62^20) = 1.4196007e-33
.