mirror of
https://github.com/XFox111/PasswordGeneratorExtension.git
synced 2026-04-22 08:08:01 +03:00
a4de3139bf
* Force no-wrap for special characters tooltip (resolves #551) (#555) * Increase width of password count field in advanced generator (resolves #548) (#554) * Added password length limit in advanced generator (#552) * Added password length limit in advanced generator (resolves #547) * Add radix to parseInt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove unnecessary callback dependency Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * npm audit fix (#556) * Added length slider range limits (#557) * Added length slider range limits (resolves #546) * Fix validateMaxLimit logic Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Added password length update on input field blur (resolves #549) (#559) * Separator option for advanced password generator (#558) * Added separator option for advanced password generator (resolves #545) * Fix typos * Fixed merge typo * Update package.json * Bump @fluentui/react-components from 9.64.0 to 9.66.5 (#561) Bumps [@fluentui/react-components](https://github.com/microsoft/fluentui) from 9.64.0 to 9.66.5. - [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.64.0...@fluentui/react-components_v9.66.5) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-version: 9.66.5 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 @typescript-eslint/parser from 8.33.1 to 8.35.1 (#562) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.33.1 to 8.35.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.35.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.35.1 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.28.0 to 9.30.0 (#564) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.28.0 to 9.30.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.30.0/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-version: 9.30.0 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 from 9.28.0 to 9.30.0 (#566) Bumps [eslint](https://github.com/eslint/eslint) from 9.28.0 to 9.30.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.28.0...v9.30.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 9.30.0 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 @typescript-eslint/eslint-plugin from 8.33.1 to 8.35.1 (#563) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.33.1 to 8.35.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.35.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.35.1 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-icons from 2.0.302 to 2.0.305 (#565) Bumps [@fluentui/react-icons](https://github.com/microsoft/fluentui-system-icons) from 2.0.302 to 2.0.305. - [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-version: 2.0.305 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> * Moved default password lengths to constants (#553) * Added radix 10 for parseInt (#553) * Removed ts-expect-error microsoft/fluentui#27090 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
163 lines
4.4 KiB
TypeScript
163 lines
4.4 KiB
TypeScript
import { MIN_PASSWORD_LENGTH } from "../constants";
|
|
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);
|
|
|
|
if (options.separator && options.separatorInterval)
|
|
password = addSeparator(password, options.separator, options.separatorInterval);
|
|
|
|
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 < MIN_PASSWORD_LENGTH)
|
|
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;
|
|
}
|
|
|
|
function addSeparator(password: string, separator: string, separatorInterval: number): string
|
|
{
|
|
if (!separator || separatorInterval < 1)
|
|
return password;
|
|
|
|
const parts: string[] = [];
|
|
for (let i = 0; i < password.length; i += separatorInterval)
|
|
parts.push(password.slice(i, i + separatorInterval));
|
|
|
|
return parts.join(separator);
|
|
}
|
|
|
|
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;
|
|
|
|
separator?: string;
|
|
separatorInterval?: number;
|
|
};
|