Browse Source

Perform linting of the JavaScript code

- Add JSHint configuration file
- Rename 'length' constant
- Move time formatting to formatTime
- Move hash parsing to parseLocationHash
- Move hash updating to updateLocationHash
- Move random password generation to generatePassword
- Create settings objects for list behaviour tweaking
- Appease all other minor JSHint issues
master
Silke 3 years ago
parent
commit
2123a67edf
  1. 91
      .jshintrc
  2. 162
      static/main.js

91
.jshintrc

@ -0,0 +1,91 @@
{
// JSHint Default Configuration File (as on JSHint website)
// See http://jshint.com/docs/ for more details
"maxerr" : 50, // {int} Maximum error before stopping
// Enforcing
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
"camelcase" : true, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
"immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"latedef" : true, // true: Require variables/functions to be defined before being used
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"noempty" : true, // true: Prohibit use of empty blocks
"nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
"plusplus" : false, // true: Prohibit use of `++` and `--`
"quotmark" : true, // Quotation mark consistency:
// false : do nothing (default)
// true : ensure whatever is used is consistent
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // Unused variables:
// true : all variables, last function parameter
// "vars" : all variables only
// "strict" : all variables, all function parameters
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"maxparams" : false, // {int} Max number of formal params allowed per function
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
"maxstatements" : 10, // {int} Max number statements per function
"maxcomplexity" : 6, // {int} Max cyclomatic complexity per function
"maxlen" : 100, // {int} Max number of characters per line
"varstmt" : true, // true: Disallow any var statements. Only `let` and `const` are allowed.
// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : false, // true: Tolerate use of `== null`
"esversion" : 6, // {int} Specify the ECMAScript version to which the code must adhere.
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// (ex: `for each`, multiple try/catch, function expression…)
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
"funcscope" : false, // true: Tolerate defining variables inside control statements
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
"iterator" : false, // true: Tolerate using the `__iterator__` property
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
"laxcomma" : false, // true: Tolerate comma-first style coding
"loopfunc" : false, // true: Tolerate functions being defined in loops
"multistr" : false, // true: Tolerate multi-line strings
"noyield" : false, // true: Tolerate generator functions with no yield statement in them.
"notypeof" : false, // true: Tolerate invalid typeof operator values
"proto" : false, // true: Tolerate using the `__proto__` property
"scripturl" : false, // true: Tolerate script-targeted URLs
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
"validthis" : false, // true: Tolerate using this in a non-constructor function
// Environments
"browser" : true, // Web Browser (window, document, etc)
"browserify" : false, // Browserify (node.js code in the browser)
"couch" : false, // CouchDB
"devel" : true, // Development/debugging (alert, confirm, etc)
"dojo" : false, // Dojo Toolkit
"jasmine" : false, // Jasmine
"jquery" : false, // jQuery
"mocha" : false, // Mocha
"mootools" : false, // MooTools
"node" : false, // Node.js
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
"phantom" : false, // PhantomJS
"prototypejs" : false, // Prototype and Scriptaculous
"qunit" : false, // QUnit
"rhino" : false, // Rhino
"shelljs" : false, // ShellJS
"typed" : false, // Globals for typed array constructions
"worker" : false, // Web Workers
"wsh" : false, // Windows Scripting Host
"yui" : false, // Yahoo User Interface
// Custom Globals
"globals" : {} // additional predefined global variables
}

162
static/main.js

@ -18,16 +18,20 @@
const indexFile = "../index.json";
const listDir = "../lists/";
const language = document.querySelector('html').getAttribute('lang');
const language = document.querySelector("html").getAttribute("lang");
const defaultLength = 4;
const hashSpeed = 5; // In 10^6 attempts/second
const list = document.getElementById("list");
const length = document.getElementById("password-length");
const passwordLength = document.getElementById("password-length");
// Password list
let passwords = [];
let defaultList = "";
// Password settings
const defaultPasswordSettings = { joinChar: " ", lowerCase: true };
const shortListPasswordSettings = { joinChar: "", lowerCase: false };
// Time units
const secondsHour = 3600;
const secondsDay = 86400;
@ -39,39 +43,63 @@ let units = {
"eternity": "∞ s"
};
// Initialise the password generator.
try {
init();
}
catch(error) {
document.getElementById("error").style.display = "block";
throw error;
}
// Set the inner HTML for an element
function setHTML(selector, html) {
"use strict";
let list = document.querySelectorAll(selector);
for (let e of list) e.innerHTML = html;
for (let e of list) {
e.innerHTML = html;
}
}
// Generate a password from the loaded list
function generate() {
// Format time to a human readable format.
function formatTime(time) {
"use strict";
// Required password length
let minLength = length.value * Math.log(passwords.length) / Math.log(26);
let joinChar = " ";
let lowerCase = true;
let text = "";
if (time >= 0 && time < 2 * secondsDay) {
text = Math.round(time / secondsHour) + " " + units.hour;
} else if (time < 2 * secondsYear) {
text = Math.round(time / secondsDay) + " " + units.day;
} else if (time < secondsYear * Math.pow(10, 9)) {
text = Math.round(time / secondsYear) + " " + units.year;
} else {
text = units.eternity;
}
// Small lists have different behaviour
if (passwords.length < 1000 || passwords[0] === "😀") {
minLength = 0;
joinChar = "";
lowerCase = false;
return text;
}
// Get settings from the location hash
function parseLocationHash() {
"use strict";
const hash = window.location.hash.substring(1).split(";");
return {
list: hash[0],
length: Number(hash[1])
};
}
// Update the window location hash
function updateLocationHash() {
"use strict";
if (window.location.hash ||
list.value !== defaultList ||
Number(passwordLength.value) !== defaultLength)
{
window.location.hash = "#" + list.value + ";" + passwordLength.value;
document.querySelector("a.generate.button").href = window.location.hash;
}
}
// Generate a random password from the loaded list
function generatePassword(length, lowerCase) {
"use strict";
// Array for password generation
const random = new Uint32Array(length.value);
const random = new Uint32Array(passwordLength.value);
let gen = [];
// Fill the array with random values
@ -90,14 +118,35 @@ function generate() {
gen.push(w);
}
return gen;
}
// Generate a password from the loaded list and show it.
function generate() {
"use strict";
// Required password passwordLength
let minLength = passwordLength.value * Math.log(passwords.length) / Math.log(26);
let settings = defaultPasswordSettings;
// Small lists have different behaviour
if (passwords.length < 1000 || passwords[0] === "😀") {
minLength = 0;
settings = shortListPasswordSettings;
}
// Generate a random password
const gen = generatePassword(passwordLength.value, settings.lowerCase);
// Check if the password has as much entropy as the individual letters
if (gen.join("").length >= minLength) {
// Display the password
setHTML("h1#password", gen.join(joinChar));
setHTML("h1#password", gen.join(settings.joinChar));
} else {
// Try again
console.log(
"Not enough entropy, " + minLength + " characters required: " + gen.join(joinChar)
"Not enough entropy, " + minLength + " characters required: " +
gen.join(settings.joinChar)
);
generate();
}
@ -107,33 +156,18 @@ function generate() {
function update() {
"use strict";
const space = Math.pow(passwords.length, length.value);
const space = Math.pow(passwords.length, passwordLength.value);
const bits = Math.log(space) / Math.log(2);
const time = space / 2 / hashSpeed / Math.pow(10, 6);
let text = "";
// Make time readable
if (time >= 0 && time < 2 * secondsDay) {
text = Math.round(time / secondsHour) + " " + units.hour;
} else if (time < 2 * secondsYear) {
text = Math.round(time / secondsDay) + " " + units.day;
} else if (time < secondsYear * Math.pow(10, 9)) {
text = Math.round(time / secondsYear) + " " + units.year;
} else {
text = units.eternity;
}
// Show the results in the text
setHTML(".wordCount", passwords.length);
setHTML(".entropyBits", Math.round(bits));
setHTML(".entropyYears", text);
setHTML(".entropyYears", formatTime(time));
setHTML(".hashSpeed", hashSpeed);
// Update the URL hash
if (list.value !== defaultList || Number(length.value) !== defaultLength) {
window.location.hash = '#' + list.value + ';' + length.value;
document.querySelector("a.generate.button").href = window.location.hash
}
updateLocationHash();
// Generate a new password
generate();
@ -161,14 +195,15 @@ function appendList(name, data) {
let list = document.getElementById("list");
// Add description option
let option = new Option(data['_description']);
let option = new Option(data._description);
option.disabled = true;
list.add(option);
// Add other options
for (let l in data) {
if (l.substring(0, 1) === "_") continue;
list.add(new Option(data[l], name + "/" + l));
if (data.hasOwnProperty(l) && l.substring(0, 1) !== "_") {
list.add(new Option(data[l], name + "/" + l));
}
}
}
@ -176,11 +211,11 @@ function appendList(name, data) {
function init() {
"use strict";
// Set callbacks for list/length changes
// Set callbacks for list/passwordLength changes
list.onchange = () => {
loadPasswords(list.value);
};
length.onchange = () => {
passwordLength.onchange = () => {
update();
};
@ -198,21 +233,30 @@ function init() {
// Save units
units = data[language].units;
// Set list and length to defaults
return lists;
})
.then((lists) => {
// Set list and passwordLength to defaults
defaultList = language + "/" + lists.default;
let listName = defaultList;
let pwLength = defaultLength;
let conf = {list: defaultList, length: defaultLength};
// Override list/length from location
// Override list/passwordLength from location
if (window.location.hash) {
const hash = window.location.hash.substring(1).split(';');
listName = hash[0];
pwLength = Number(hash[1]);
conf = parseLocationHash();
}
// Set the selectors to the correct values and load the list.
list.value = listName;
length.value = pwLength;
loadPasswords(listName);
list.value = conf.list;
passwordLength.value = conf.length;
loadPasswords(conf.list);
});
}
// Initialise the password generator.
try {
init();
}
catch(error) {
document.getElementById("error").style.display = "block";
throw error;
}
Loading…
Cancel
Save