passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
189 lines (178 loc) • 5.74 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 3.3.0
* Secret generator complexity
* Entropy calculate following https://generatepasswords.org/how-to-calculate-entropy/
*/
import PassphraseGeneratorWords from "./PassphraseGeneratorWords";
import GraphemeSplitter from "grapheme-splitter";
const STRENGTH = [
{
id: 'not_available',
label: 'n/a',
strength: 0
},
{
id: 'very-weak',
label: 'Very weak',
strength: 1
},
{
id: 'weak',
label: 'Weak',
strength: 60
},
{
id: 'fair',
label: 'Fair',
strength: 80
},
{
id: 'strong',
label: 'Strong',
strength: 112
},
{
id: 'very-strong',
label: 'Very strong',
strength: 128
}
];
// @todo the tool should use the masks provided by the background page.
const MASKS = [
{
"name": "upper",
"label": "A-Z",
"characters": ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
"active": true
},
{
"name": "lower",
"label": "a-z",
"characters": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"],
"active": true
},
{
"name": "digit",
"label": "0-9",
"characters": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
"active": true
},
{
"name": "special_char1",
"label": "# $ % & @ ^ ~",
"characters": ["#", "$", "%", "&", "@", "^", "~"],
"active": true
},
{
"name": "parenthesis",
"label": "{ [ ( | ) ] ] }",
"characters": ["{", "(", "[", "|", "]", ")", "}"],
"active": true
},
{
"name": "special_char2",
"label": ". , : ;",
"characters": [".", ",", ":", ";"],
"active": true
},
{
"name": "special_char3",
"label": "' \" `",
"characters": ["'", "\"", "`"],
"active": true
},
{
"name": "special_char4",
"label": "/ \\ _ -",
"characters": ["/", "\\", "_", "-"],
"active": true
},
{
"name": "special_char5",
"label": "< * + ! ? =",
"characters": ["<", "*", "+", "!", "?", "="],
"active": true
},
{
"name": "emoji",
"label": "😘",
// Based on the initial emoticons block (introduce in unicode v6), not updated since 2015 (unicode v8), see https://en.wikipedia.org/wiki/Emoticons_(Unicode_block)
"characters": [
"😀", "😁", "😂", "😃", "😄", "😅", "😆", "😇", "😈", "😉",
"😊", "😋", "😌", "😍", "😎", "😏", "😐", "😑", "😒", "😓",
"😔", "😕", "😖", "😗", "😘", "😙", "😚", "😛", "😜", "😝",
"😞", "😟", "😠", "😡", "😢", "😣", "😤", "😥", "😦", "😧",
"😨", "😩", "😪", "😫", "😬", "😭", "😮", "😯", "😰", "😱",
"😲", "😳", "😴", "😵", "😶", "😷", "😸", "😹", "😺", "😻",
"😼", "😽", "😾", "😿", "🙀", "🙁", "🙂", "🙃", "🙄", "🙅",
"🙆", "🙇", "🙈", "🙉", "🙊", "🙋", "🙌", "🙍", "🙎", "🙏",
],
}
];
const NUMBER_OF_ASCII_CHARACTER = 128;
const NUMBER_OF_WORD_CASE = 3;
export const SecretGeneratorComplexity = {
/**
* Calculate a password entropy.
* @param {string} password The password
* @returns {Number}
*/
entropyPassword: (password = '') => {
const splitter = new GraphemeSplitter();
const passwordCharacters = splitter.splitGraphemes(password);
let maskSize = 0;
for (const mask of MASKS) {
const useMask = passwordCharacters.some(character => mask.characters.includes(character));
if (useMask) {
maskSize += mask.characters.length;
}
}
return calculEntropy(passwordCharacters.length, maskSize);
},
/**
* Calculate a passphrase entropy.
* @param {integer} numberOfWords The number of words
* @param {string} separator The passphrase separator
* @returns {Number}
*/
entropyPassphrase: (numberOfWords = 0, separator = '') => {
const words = PassphraseGeneratorWords['en-UK'];
// determine a constant for separator
const maskSize = (separator.length * NUMBER_OF_ASCII_CHARACTER) + words.length + NUMBER_OF_WORD_CASE;
return calculEntropy(numberOfWords, maskSize);
},
/**
* Get the strength relative to an entropy
* @param {number} entropy The entropy
* @returns {{strength: number, id: string, label: string}|{strength: number, id: string, label: string}|{strength: number, id: string, label: string}|{strength: number, id: string, label: string}|{strength: number, id: string, label: string}}
*/
strength: (entropy = 0) => STRENGTH.reduce((accumulator, item) => {
if (!accumulator) {
return item;
}
if (item.strength > accumulator.strength && entropy >= item.strength) {
return item;
}
return accumulator;
}),
calculEntropy
};
/**
* Calculate the entropy regarding the given primitives.
* @param length {int} The number of characters
* @param maskSize {int} The number of possibility for each character
* @return {int}
*/
function calculEntropy(length, maskSize) {
return (length && maskSize) ? length * (Math.log(maskSize) / Math.log(2)) : 0;
}