I created a random code generator script via Google apps script. My goal is to generate 6000 uniques random codes (in spreadsheet) as fast as possible. The following javascript code crashes with Google spreadsheet apps script --> too long to execute and the same code under python generates 20,000 random codes in less than 1 second... I'm not a JS ninja, do you have any idea to optimize the JS code below ?
Code JS
function main(nbre_car,nbre_pass,number,letter_maj,letter_min,spec_car){
var nbre_car = 6;
var nbre_pass = 6000;
var number = true;
var letter_maj = false;
var letter_min = false;
var spec_car = false;
var prefixe="FOULE";
return generate_password(nbre_car,nbre_pass,number,letter_maj,letter_min,spec_car,prefixe)
}
function combinaison_possible(char_number,lenght_possible_char){
combinaison_nbre=Math.pow(lenght_possible_char,char_number)
return combinaison_nbre
}
function generate_password(nbre_car,nbre_pass,number=true,letter_maj=false,letter_min=false,spec_car=false,prefixe="") {
if (Number.isInteger(nbre_car)&&Number.isInteger(nbre_pass)){
}
else{
return "Veuillez rentrer un nombre entier pour les champs en bleu"
}
var nbre_car = nbre_car || 10;
var nbre_pass = nbre_pass || 3;
var pass_number="123456789";
var pass_letter_maj="ABCDEFGHIJKLMNPQRSTUVWXYZ";
var pass_letter_min="abcdefghijklmnpqrstuvwxyz"
var pass_spec_car="'(-è_çà)=:;,!."
// Check entry type
// Create an empty map which will contain all password
var col = new Map([]);
var prefixe=prefixe;
var list_char='';
list_char= letter_maj == true ? list_char pass_letter_maj : list_char
list_char= number == true ? list_char pass_number : list_char
list_char= letter_min == true ? list_char pass_letter_min : list_char
list_char= spec_car == true ? list_char pass_spec_car : list_char
// Teste les combinaisons possible entre le nombre de caractère demandés pour le password et la liste disponible
if (combinaison_possible(nbre_car,list_char.length)>=nbre_pass) {
// Création des mots de passe unique
while(col.size===0||nbre_pass>col.size) {
Logger.log("col.size : " col.size)
Logger.log("nbre_pass : " nbre_pass)
search_new_pass=true;
while (search_new_pass==true){
pass=create_one_password(nbre_car,list_char,prefixe)
Logger.log('nom du password : ' pass)
if (verify_unique(col,pass)!=true)
col.set({}, pass);
Logger.log("valeur de col : " col)
search_new_pass=false;
}
}
}
else{
col = [];
col.push("Vous avez demander trop de mots de passe, cela va créer des doublons,Veuillez diminuer le nombre de mots de passe à afficher");
}
final_values=[...col.values()];
//Logger.log('valeur final de col : ' final_values)
console.log(Array.from(col.values()));
return Array.from(col.values());
}
function create_one_password(nbre_car,list_char,prefixe) {
var nbre_car = nbre_car;
s = '', r = list_char;
for (var i=0; i < nbre_car; i ) {
s = r.charAt(Math.floor(Math.random()*r.length));
}
return prefixe s;
}
Code Python
import random
def combinaison_possible(char_number,lenght_possible_char):
combinaison_nbre=pow(lenght_possible_char,char_number)
return combinaison_nbre
def generate_password(nbre_car,nbre_pass,number=True,letter_maj=True,letter_min=True,spec_car=True,prefixe="FOULE") :
if(not isinstance(nbre_car,int) and isinstance(not nbre_pass,int)) :
print( "Veuillez rentrer un nombre entier pour les champs en bleu")
nbre_car = nbre_car
nbre_pass = nbre_pass
pass_number="123456789"
pass_letter_maj="ABCDEFGHIJKLMNPQRSTUVWXYZ"
pass_letter_min="abcdefghijklmnpqrstuvwxyz"
pass_spec_car="!@#$%^&*()_ "
prefixe=prefixe
list_char=''
col={}
longueur_col=len(col)
list_char= list_char pass_letter_maj if letter_maj else list_char
list_char= list_char pass_letter_min if letter_min else list_char
list_char= list_char pass_number if number else list_char
list_char= list_char pass_spec_car if spec_car else list_char
if (combinaison_possible(nbre_car,len(list_char))>=nbre_pass) :
while(len(col)==0 or nbre_pass>len(col)):
longueur_col=len(col)
search_new_pass=True
while (search_new_pass==True):
pass_word = prefixe ''.join(random.choice(list_char) for i in range(nbre_car))
if pass_word not in col:
col[longueur_col]=pass_word
search_new_pass=False
print (col)
else :
print("Le nombre de mot de passe à générer est trop important par rapport au nombre de caractères possible")
generate_password(6,20000)
CodePudding user response:
Performance-wise, the main difference between the Apps Script and Python versions is that the Apps Script code logs about 20,000 values in the Apps Script console, which is slow, while the Python code outputs 1 value.
The Apps Script code has several syntactical and semantical errors, including:
verify_unique()
is undefinedcol.set({}, pass)
does not make sense; perhaps use anArray
instead of aMap
, find if a value is already in the list withcol.includes(pass)
, insert values withcol.push(pass)
, and usecol
instead ofArray.from(col.values())
to retrieve the valuesvar prefixe = prefixe;
is superfluous
See Apps Script at Stack Overflow and Clean Code JavaScript.
CodePudding user response:
I think the code could be quite a bit easier. I did not study your code extensively. But this would be my approach to solve the problem. As you can see it takes less than one second to generate 20'000 passwords.
What actually really takes a long time is the duplicate check.
Aside from thath be careful when generating passwords without a cryptographically secure random algorithm.
Please have a look at this for how to use Crypto.getRandomValues()
const CHARACTER_POOL =
"123456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz'(-è_çà)=:;,!.";
const PASSWORDS_TO_GENERATE = 20000;
const PASSWORD_LENGTH = 6;
const PREFIX = "";
const createPassword = () => {
let password = "";
for (let i = 0; i < PASSWORD_LENGTH; i ) {
// this is not secure
password = CHARACTER_POOL.charAt(
Math.floor(Math.random() * CHARACTER_POOL.length)
);
}
return `${PREFIX}${password}`;
};
const generatePassword = () => {
const passwords = [];
while (passwords.length < PASSWORDS_TO_GENERATE) {
const password = createPassword();
if (!passwords.includes(password)) {
passwords.push(password);
}
}
return passwords;
};
const start = new Date().getTime();
const passwords = generatePassword();
console.log(`It took ${(new Date().getTime() - start) / 1000} to generate ${passwords.length} passwords`);
console.log(passwords);