mirror of
https://github.com/XFox111/PasswordGeneratorExtension.git
synced 2026-04-22 08:08:01 +03:00
Major 5.0 (#469)
* Advanced generator, UI overhaul (#449) * Major overhaul: - Added advanced generator - Removed "Insert and copy" feature - Moved settings to extension options - General refactoring * Updated custom character options for default generator (#447) * Added state save for advanced generator mode * Fixed state save for advanced password generator * Updated extension description * Minor UI fixes: - Fixed Options UI not displaying in Google Chrome - Fixed Quick Options menus overflowing on some locales - Fixed Advanced generator configuration UI clipping when window height is too small - Fixed divider in Options UI taking up all available space * Minor UI/UX changes and fixes: - Fixed locale in Advanced generator toast notifications - Added toast notification for copying a single password in Advanced generator - Moved custom characters input lables to placeholders - Fixed minor type issues - Removed duplicate "About" text - Fixed input fields alignment in Options - Added "disabled" state for "Include Custom" option in Quick settings * Bump @typescript-eslint/parser from 8.16.0 to 8.19.1 (#468) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.16.0 to 8.19.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.19.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @eslint/js from 9.16.0 to 9.18.0 (#467) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.16.0 to 9.18.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/commits/v9.18.0/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @fluentui/react-components from 9.56.3 to 9.57.0 (#466) Bumps [@fluentui/react-components](https://github.com/microsoft/fluentui) from 9.56.3 to 9.57.0. - [Release notes](https://github.com/microsoft/fluentui/releases) - [Changelog](https://github.com/microsoft/fluentui/blob/master/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/fluentui/compare/@fluentui/react-components_v9.56.3...@fluentui/react-components_v9.57.0) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump wxt from 0.19.17 to 0.19.24 (#465) Bumps [wxt](https://github.com/wxt-dev/wxt) from 0.19.17 to 0.19.24. - [Release notes](https://github.com/wxt-dev/wxt/releases) - [Commits](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.17...wxt-v0.19.24) --- updated-dependencies: - dependency-name: wxt dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump eslint from 9.16.0 to 9.18.0 (#464) Bumps [eslint](https://github.com/eslint/eslint) from 9.16.0 to 9.18.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.16.0...v9.18.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump eslint-plugin-react from 7.37.2 to 7.37.4 (#463) Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.2 to 7.37.4. - [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases) - [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.2...v7.37.4) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump typescript from 5.7.2 to 5.7.3 (#462) Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.2 to 5.7.3. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.2...v5.7.3) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump @typescript-eslint/eslint-plugin from 8.16.0 to 8.19.1 (#461) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.16.0 to 8.19.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.19.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump wdzeng/chrome-extension from 1.2.4 to 1.3.0 (#450) * Bump wdzeng/chrome-extension from 1.2.4 to 1.3.0 Bumps [wdzeng/chrome-extension](https://github.com/wdzeng/chrome-extension) from 1.2.4 to 1.3.0. - [Release notes](https://github.com/wdzeng/chrome-extension/releases) - [Commits](https://github.com/wdzeng/chrome-extension/compare/v1.2.4...v1.3.0) --- updated-dependencies: - dependency-name: wdzeng/chrome-extension dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Optimized CD workflow --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene@xfox111.net> * Bump @fluentui/react-icons from 2.0.266 to 2.0.270 (#458) Bumps [@fluentui/react-icons](https://github.com/microsoft/fluentui-system-icons) from 2.0.266 to 2.0.270. - [Changelog](https://github.com/microsoft/fluentui-system-icons/blob/main/fluentui-android-system-icons-release.yml) - [Commits](https://github.com/microsoft/fluentui-system-icons/commits) --- updated-dependencies: - dependency-name: "@fluentui/react-icons" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @wxt-dev/module-react from 1.1.2 to 1.1.3 (#455) Bumps [@wxt-dev/module-react](https://github.com/wxt-dev/wxt/tree/HEAD/packages/module-react) from 1.1.2 to 1.1.3. - [Release notes](https://github.com/wxt-dev/wxt/releases) - [Changelog](https://github.com/wxt-dev/wxt/blob/main/packages/module-react/CHANGELOG.md) - [Commits](https://github.com/wxt-dev/wxt/commits/module-react-v1.1.3/packages/module-react) --- updated-dependencies: - dependency-name: "@wxt-dev/module-react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump globals from 15.12.0 to 15.14.0 (#452) Bumps [globals](https://github.com/sindresorhus/globals) from 15.12.0 to 15.14.0. - [Release notes](https://github.com/sindresorhus/globals/releases) - [Commits](https://github.com/sindresorhus/globals/compare/v15.12.0...v15.14.0) --- updated-dependencies: - dependency-name: globals dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,128 +0,0 @@
|
||||
import { GeneratorOptions } from "./storage";
|
||||
|
||||
const Characters =
|
||||
{
|
||||
Uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
Lowercase: "abcdefghijklmnopqrstuvwxyz",
|
||||
Numeric: "1234567890",
|
||||
Special: "!#$%&*+-=?@^_"
|
||||
};
|
||||
|
||||
const Similar: string = "iIl1Lo0O";
|
||||
const Ambiguous: string = "{}[]()/\\'\"`~,;:.<>";
|
||||
|
||||
export const CharacterHints = { ...Characters, Similar, Ambiguous };
|
||||
|
||||
/**
|
||||
* Generates a random password
|
||||
* @param options Options for password generation
|
||||
* @returns Randomly generated password
|
||||
* @throws Error if options are invalid
|
||||
*/
|
||||
export function GeneratePassword(options: GeneratorOptions): string
|
||||
{
|
||||
ValidateOptions(options);
|
||||
|
||||
let password: string = GetRequiredCharacters(options);
|
||||
const availableCharacters: string = GetAvailableCharacters(options);
|
||||
|
||||
for (let i = password.length; i < options.Length; i++)
|
||||
{
|
||||
const character: string = PickRandomFromArray(availableCharacters);
|
||||
|
||||
if (options.ExcludeRepeating && password.includes(character))
|
||||
i--;
|
||||
else
|
||||
password += character;
|
||||
}
|
||||
|
||||
password = ShuffleString(password);
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates options for password generation
|
||||
* @param options Options for password generation
|
||||
* @throws Error if options are invalid
|
||||
*/
|
||||
export function ValidateOptions(options: GeneratorOptions): void
|
||||
{
|
||||
if (options.Length < 4)
|
||||
throw new Error(i18n.t("errors.too_short"));
|
||||
|
||||
const availableCharacters: string = GetAvailableCharacters(options);
|
||||
|
||||
if (availableCharacters.length < 1)
|
||||
throw new Error(i18n.t("errors.no_characters"));
|
||||
|
||||
if (options.ExcludeRepeating && options.Length > availableCharacters.length)
|
||||
throw new Error(i18n.t("errors.too_long"));
|
||||
}
|
||||
|
||||
// Returns a string containing all characters that are available for password generation
|
||||
function GetAvailableCharacters(options: GeneratorOptions): string
|
||||
{
|
||||
let availableCharacters: string = "";
|
||||
|
||||
for (const [key, value] of Object.entries(Characters))
|
||||
if (options[key as keyof GeneratorOptions])
|
||||
availableCharacters += value;
|
||||
|
||||
if (options.ExcludeSimilar)
|
||||
availableCharacters = availableCharacters.replace(new RegExp(`[${Similar}]`, "g"), "");
|
||||
|
||||
if (options.Special && !options.ExcludeAmbiguous)
|
||||
availableCharacters += Ambiguous;
|
||||
|
||||
return availableCharacters;
|
||||
}
|
||||
|
||||
// Returns a string containing all characters from every available set that are required for password generation
|
||||
function GetRequiredCharacters(options: GeneratorOptions): string
|
||||
{
|
||||
let result: string = "";
|
||||
const characters: Record<string, string> = Object.assign({}, Characters);
|
||||
|
||||
if (!options.ExcludeAmbiguous)
|
||||
characters.Special += Ambiguous;
|
||||
|
||||
if (options.ExcludeSimilar)
|
||||
for (const key of Object.keys(characters))
|
||||
characters[key] = characters[key].replace(new RegExp(`[${Similar}]`, "g"), "");
|
||||
|
||||
for (const [key, value] of Object.entries(characters))
|
||||
if (options[key as keyof GeneratorOptions])
|
||||
result += PickRandomFromArray(value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Picks a random character from a string
|
||||
function PickRandomFromArray(array: string): string
|
||||
{
|
||||
return array[GetRandomInt(0, array.length)];
|
||||
}
|
||||
|
||||
// See https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
// min is inclusive, max is exclusive
|
||||
function GetRandomInt(min: number, max: number): number
|
||||
{
|
||||
const arr = new Uint16Array(1);
|
||||
crypto.getRandomValues(arr); // Using crypto instead of Math.random() as a CSPRNG
|
||||
return Math.floor((arr[0] / 65_536) * (max - min)) + min;
|
||||
}
|
||||
|
||||
// Shuffles a string using Fisher-Yates algorithm and CSPRNG
|
||||
// See https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
|
||||
function ShuffleString(str: string): string
|
||||
{
|
||||
const arr = str.split("");
|
||||
|
||||
for (let i = arr.length - 1; i > 0; i--)
|
||||
{
|
||||
const j = GetRandomInt(0, i + 1);
|
||||
[arr[i], arr[j]] = [arr[j], arr[i]];
|
||||
}
|
||||
|
||||
return arr.join("");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
||||
// Based on ealamiLabs - Password generator (https://github.com/ealamiLabs/password-generator)
|
||||
// licensed under MIT
|
||||
|
||||
import dictionary from "./dictionary.json";
|
||||
import { getBooleanSequence, getRandomInt } from "./randomUtils";
|
||||
|
||||
/* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 ealamiLabs
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
export default function generatePassphrase(options: PassphraseProps): string
|
||||
{
|
||||
const words: string[] = [];
|
||||
|
||||
for (let i = 0; i < options.wordCount; i++)
|
||||
{
|
||||
const word: string = dictionary[getRandomInt(0, dictionary.length)].word;
|
||||
|
||||
if (!options.allowRepeating && words.includes(word))
|
||||
i--;
|
||||
else
|
||||
words.push(word);
|
||||
}
|
||||
|
||||
let result: string = words.join(options.separator).toLocaleLowerCase();
|
||||
|
||||
console.log(result);
|
||||
|
||||
if (options.swapCharacters)
|
||||
result = swapCharacters(result);
|
||||
|
||||
if (options.randomizeCase)
|
||||
result = RandomUpperCase(result);
|
||||
|
||||
console.log(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function RandomUpperCase(passphrase: string): string
|
||||
{
|
||||
const sequence: boolean[] = getBooleanSequence(passphrase.length);
|
||||
let result: string = "";
|
||||
|
||||
for (let i = 0; i < passphrase.length; i++)
|
||||
result += sequence[i] ? passphrase[i].toLocaleUpperCase() : passphrase[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function swapCharacters(passphrase: string): string
|
||||
{
|
||||
const sequence: boolean[] = getBooleanSequence(passphrase.length);
|
||||
let result: string = "";
|
||||
|
||||
for (let i = 0; i < passphrase.length; i++)
|
||||
if (sequence[i])
|
||||
switch (passphrase[i].toLocaleLowerCase())
|
||||
{
|
||||
case "a":
|
||||
result += getRandomInt(0, 100) < 50 ? "@" : "4";
|
||||
break;
|
||||
case "e":
|
||||
result += "3";
|
||||
break;
|
||||
case "i":
|
||||
result += "!";
|
||||
break;
|
||||
case "s":
|
||||
result += getRandomInt(0, 100) < 50 ? "$" : "5";
|
||||
break;
|
||||
default:
|
||||
result += passphrase[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
result += passphrase[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export type PassphraseProps =
|
||||
{
|
||||
wordCount: number;
|
||||
swapCharacters: boolean;
|
||||
randomizeCase: boolean;
|
||||
allowRepeating: boolean;
|
||||
separator: string;
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
import { pickRandomFromArray, shuffleString } from "./randomUtils";
|
||||
|
||||
const Characters =
|
||||
{
|
||||
uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
lowercase: "abcdefghijklmnopqrstuvwxyz",
|
||||
numeric: "1234567890",
|
||||
special: "!#$%&*+-=?@^_"
|
||||
};
|
||||
|
||||
const similar: string = "iIl1Lo0O";
|
||||
const ambiguous: string = "{}[]()/\\'\"`~,;:.<>";
|
||||
|
||||
export const CharacterHints = { ...Characters, similar, ambiguous };
|
||||
|
||||
/**
|
||||
* Generates a random password
|
||||
* @param options Options for password generation
|
||||
* @returns Randomly generated password
|
||||
* @throws Error if options are invalid
|
||||
*/
|
||||
export function generatePassword(options: PasswordProps): string
|
||||
{
|
||||
validateOptions(options);
|
||||
|
||||
let password: string = getRequiredCharacters(options);
|
||||
const availableCharacters: string = getAvailableCharacters(options);
|
||||
|
||||
for (let i = password.length; i < options.length; i++)
|
||||
{
|
||||
const character: string = pickRandomFromArray(availableCharacters);
|
||||
|
||||
if (options.excludeRepeating && password.includes(character))
|
||||
i--;
|
||||
else
|
||||
password += character;
|
||||
}
|
||||
|
||||
password = shuffleString(password);
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates options for password generation
|
||||
* @param options Options for password generation
|
||||
* @throws Error if options are invalid
|
||||
*/
|
||||
export function validateOptions(options: PasswordProps): void
|
||||
{
|
||||
if (options.length < 4)
|
||||
throw new Error(i18n.t("errors.too_short"));
|
||||
|
||||
const availableCharacters: string = getAvailableCharacters(options);
|
||||
|
||||
if (availableCharacters.length < 1)
|
||||
throw new Error(i18n.t("errors.no_characters"));
|
||||
|
||||
if (options.excludeRepeating && options.length > availableCharacters.length)
|
||||
throw new Error(i18n.t("errors.too_long"));
|
||||
}
|
||||
|
||||
// Returns a string containing all characters that are available for password generation
|
||||
function getAvailableCharacters(options: PasswordProps): string
|
||||
{
|
||||
let availableCharacters: string = "";
|
||||
|
||||
for (const [key, value] of Object.entries(Characters))
|
||||
if (options[key as keyof PasswordProps])
|
||||
availableCharacters += value;
|
||||
|
||||
if (options.custom && options.customSet.length > 0)
|
||||
availableCharacters += options.customSet;
|
||||
|
||||
if (options.excludeSimilar)
|
||||
availableCharacters = availableCharacters.replace(new RegExp(`[${similar}]`, "g"), "");
|
||||
|
||||
if (options.special && !options.excludeAmbiguous)
|
||||
availableCharacters += ambiguous;
|
||||
|
||||
if (options.excludeCustom.length > 0)
|
||||
availableCharacters = availableCharacters.replace(new RegExp(`[${options.excludeCustom}]`, "g"), "");
|
||||
|
||||
return availableCharacters;
|
||||
}
|
||||
|
||||
// Returns a string containing all characters from every available set that are required for password generation
|
||||
function getRequiredCharacters(options: PasswordProps): string
|
||||
{
|
||||
let result: string = "";
|
||||
const characters: Record<string, string> = Object.assign({}, Characters);
|
||||
|
||||
if (!options.excludeAmbiguous)
|
||||
characters.special += ambiguous;
|
||||
|
||||
if (options.custom && options.customSet.length > 0)
|
||||
characters.custom = options.customSet;
|
||||
|
||||
for (const key of Object.keys(characters))
|
||||
{
|
||||
if (options.excludeSimilar)
|
||||
characters[key] = characters[key].replace(new RegExp(`[${similar}]`, "g"), "");
|
||||
|
||||
if (options.excludeCustom.length > 0)
|
||||
characters[key] = characters[key].replace(new RegExp(`[${options.excludeCustom}]`, "g"), "");
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(characters))
|
||||
if (options[key as keyof PasswordProps])
|
||||
for (let i = 0; i < (options[key as keyof PasswordProps] as number); i++)
|
||||
{
|
||||
if (value.length < 1)
|
||||
continue;
|
||||
|
||||
const char = pickRandomFromArray(value);
|
||||
|
||||
if (options.excludeRepeating && result.includes(char))
|
||||
i--;
|
||||
else
|
||||
result += char;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export type PasswordProps =
|
||||
{
|
||||
length: number;
|
||||
|
||||
special: boolean | number;
|
||||
numeric: boolean | number;
|
||||
lowercase: boolean | number;
|
||||
uppercase: boolean | number;
|
||||
custom: boolean | number;
|
||||
|
||||
customSet: string;
|
||||
|
||||
excludeSimilar: boolean;
|
||||
excludeAmbiguous: boolean;
|
||||
|
||||
excludeRepeating: boolean;
|
||||
excludeCustom: string;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
// Picks a random character from a string
|
||||
export function pickRandomFromArray(array: string): string
|
||||
{
|
||||
return array[getRandomInt(0, array.length)];
|
||||
}
|
||||
|
||||
// See https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
// min is inclusive, max is exclusive
|
||||
export function getRandomInt(min: number, max: number): number
|
||||
{
|
||||
const arr = new Uint16Array(1);
|
||||
crypto.getRandomValues(arr); // Using crypto instead of Math.random() as a CSPRNG
|
||||
return Math.floor((arr[0] / 65_536) * (max - min)) + min;
|
||||
}
|
||||
|
||||
// Shuffles a string using Fisher-Yates algorithm and CSPRNG
|
||||
// See https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
|
||||
export function shuffleString(str: string): string
|
||||
{
|
||||
const arr = str.split("");
|
||||
|
||||
for (let i = arr.length - 1; i > 0; i--)
|
||||
{
|
||||
const j = getRandomInt(0, i + 1);
|
||||
[arr[i], arr[j]] = [arr[j], arr[i]];
|
||||
}
|
||||
|
||||
return arr.join("");
|
||||
}
|
||||
|
||||
export function getBooleanSequence(length: number): boolean[]
|
||||
{
|
||||
const arr = new Uint8Array(Math.ceil(length / 8));
|
||||
crypto.getRandomValues(arr);
|
||||
|
||||
const result: boolean[] = [];
|
||||
|
||||
for (let i = 0; i < length; i++)
|
||||
{
|
||||
const byte = arr[Math.floor(i / 8)];
|
||||
const bit = byte & (1 << (i % 8));
|
||||
result.push(bit !== 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { InfoLabel, Label, LabelProps, Slot } from "@fluentui/react-components";
|
||||
|
||||
// FIXME: Remove ts-ignore comments once slots override fix is released
|
||||
// Tracker: https://github.com/microsoft/fluentui/issues/27090
|
||||
|
||||
export default function infoLabel(label: string, hint: string): Slot<typeof Label>
|
||||
{
|
||||
// @ts-expect-error See FIXME
|
||||
return {
|
||||
children: (_: unknown, props: LabelProps) =>
|
||||
<InfoLabel { ...props } info={ hint }>
|
||||
{ label }
|
||||
</InfoLabel>
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Manifest } from "webextension-polyfill";
|
||||
export const personalLinks =
|
||||
{
|
||||
website: "https://xfox111.net",
|
||||
twitter: "https://twitter.com/xfox111",
|
||||
social: "https://bsky.app/profile/xfox111.net",
|
||||
donation: "https://buymeacoffee.com/xfox111"
|
||||
};
|
||||
|
||||
|
||||
@@ -2,5 +2,4 @@ export default class ExtensionOptions
|
||||
{
|
||||
public MinLength: number = 4;
|
||||
public MaxLength: number = 32;
|
||||
public ContextMenu: boolean = true;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,13 @@ export default class GeneratorOptions
|
||||
public Numeric: boolean = true;
|
||||
public Lowercase: boolean = true;
|
||||
public Uppercase: boolean = true;
|
||||
public Custom: boolean = false;
|
||||
|
||||
public ExcludeSimilar: boolean = true;
|
||||
public ExcludeAmbiguous: boolean = true;
|
||||
|
||||
public ExcludeRepeating: boolean = false;
|
||||
public ExcludeCustom: boolean = false;
|
||||
|
||||
public ExcludeCustomSet: string = "";
|
||||
public IncludeCustomSet: string = "";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user