1
0
mirror of https://github.com/XFox111/PasswordGeneratorExtension.git synced 2026-04-22 08:08:01 +03:00

Minor 5.1.0 (#560)

* 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>
This commit is contained in:
2025-07-01 11:25:32 +03:00
committed by GitHub
parent 5d8037e767
commit a4de3139bf
18 changed files with 994 additions and 907 deletions
@@ -17,6 +17,6 @@ export const useStyles = makeStyles({
{ {
display: "grid", display: "grid",
alignItems: "center", alignItems: "center",
gridTemplateColumns: "24px 24px 56px", gridTemplateColumns: "24px 24px 60px",
} }
}); });
@@ -14,7 +14,7 @@ export default function GeneratorForm(props: GeneratorFormProps): ReactElement
const setPasswordCount = useCallback((_: any, e: InputOnChangeData) => const setPasswordCount = useCallback((_: any, e: InputOnChangeData) =>
{ {
const n = parseInt(e.value ?? "1"); const n = parseInt(e.value ?? "1", 10);
private_setPasswordCount(isNaN(n) || n < 1 ? null : Math.min(n, 1000)); private_setPasswordCount(isNaN(n) || n < 1 ? null : Math.min(n, 1000));
}, []); }, []);
@@ -27,7 +27,7 @@ export default function PassphraseSection(props: GeneratorProps): ReactElement
const setWordCount = useCallback((_: any, e: InputOnChangeData) => const setWordCount = useCallback((_: any, e: InputOnChangeData) =>
{ {
const n = parseInt(e.value ?? ""); const n = parseInt(e.value ?? "", 10);
private_setWordCount(isNaN(n) || n < 1 ? null : Math.min(n, 100)); private_setWordCount(isNaN(n) || n < 1 ? null : Math.min(n, 100));
}, []); }, []);
@@ -4,12 +4,13 @@ import * as fui from "@fluentui/react-components";
import { ReactElement } from "react"; import { ReactElement } from "react";
import { GeneratorProps } from "../Page"; import { GeneratorProps } from "../Page";
import GeneratorForm from "../components/GeneratorForm"; import GeneratorForm from "../components/GeneratorForm";
import { DEFAULT_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from "@/utils/constants";
// TODO: needs refactoring // TODO: needs refactoring
export default function PasswordSection(props: GeneratorProps): ReactElement export default function PasswordSection(props: GeneratorProps): ReactElement
{ {
const [state, private_setState] = useState<PasswordSectionState>({ const [state, private_setState] = useState<PasswordSectionState>({
length: 8, length: DEFAULT_PASSWORD_LENGTH,
enableUppercase: true, uppercaseCount: 1, enableUppercase: true, uppercaseCount: 1,
enableLowercase: true, lowercaseCount: 1, enableLowercase: true, lowercaseCount: 1,
enableNumeric: true, numericCount: 1, enableNumeric: true, numericCount: 1,
@@ -19,7 +20,11 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
excludeSimilar: true, excludeSimilar: true,
excludeAmbiguous: true, excludeAmbiguous: true,
excludeRepeating: false, excludeRepeating: false,
excludeCustom: false, excludeCustomSet: "" excludeCustom: false, excludeCustomSet: "",
enableSeparator: false,
separator: "-",
separatorInterval: DEFAULT_PASSWORD_LENGTH / 2
}); });
const cls = useStyles(); const cls = useStyles();
@@ -31,9 +36,9 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
const setLength = useCallback((_: any, e: fui.InputOnChangeData) => const setLength = useCallback((_: any, e: fui.InputOnChangeData) =>
{ {
const n = parseInt(e.value ?? ""); const n = parseInt(e.value ?? "", 10);
setState({ length: isNaN(n) || n < 1 ? null : n }); setState({ length: isNaN(n) || n < 1 ? null : Math.min(n, MAX_PASSWORD_LENGTH) });
}, [state]); }, [setState]);
const saveConfiguration = useCallback( const saveConfiguration = useCallback(
async () => await browser.storage.sync.set({ AdvancedPasswordOptions: state }), async () => await browser.storage.sync.set({ AdvancedPasswordOptions: state }),
@@ -46,7 +51,7 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
for (let i = 0; i < count; i++) for (let i = 0; i < count; i++)
passwords.push(generatePassword({ passwords.push(generatePassword({
length: state.length ?? 8, length: state.length ?? DEFAULT_PASSWORD_LENGTH,
custom: state.enableCustom ? state.customCount ?? 1 : 0, custom: state.enableCustom ? state.customCount ?? 1 : 0,
customSet: state.customSet, customSet: state.customSet,
numeric: state.enableNumeric ? state.numericCount ?? 1 : 0, numeric: state.enableNumeric ? state.numericCount ?? 1 : 0,
@@ -57,6 +62,8 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
excludeCustom: state.excludeCustom ? state.excludeCustomSet : "", excludeCustom: state.excludeCustom ? state.excludeCustomSet : "",
excludeRepeating: state.excludeRepeating, excludeRepeating: state.excludeRepeating,
excludeSimilar: state.excludeSimilar, excludeSimilar: state.excludeSimilar,
separator: state.enableSeparator ? state.separator : undefined,
separatorInterval: state.separatorInterval ?? (DEFAULT_PASSWORD_LENGTH / 2)
})); }));
props.onGenerated(passwords); props.onGenerated(passwords);
@@ -80,10 +87,38 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
onChange: (_, e) => setState({ [key]: parseCount(e.value) }) onChange: (_, e) => setState({ [key]: parseCount(e.value) })
}), [state]); }), [state]);
const setSeparatorInterval = (_: any, e: fui.InputOnChangeData) =>
{
if (!e.value)
{
setState({ separatorInterval: undefined });
return;
}
const n = parseInt(e.value, 10);
if (!isNaN(n))
setState({ separatorInterval: n < 1 ? 1 : Math.min(n, state.length ?? DEFAULT_PASSWORD_LENGTH) });
};
const updateLength = (): void =>
{
const minLength = Math.max(MIN_PASSWORD_LENGTH,
(state.enableCustom ? state.customCount ?? 1 : 0) +
(state.enableNumeric ? state.numericCount ?? 1 : 0) +
(state.enableSpecial ? state.specialCount ?? 1 : 0) +
(state.enableUppercase ? state.uppercaseCount ?? 1 : 0) +
(state.enableLowercase ? state.lowercaseCount ?? 1 : 0)
);
if (!state.length || state.length < minLength)
setState({ length: minLength });
};
return ( return (
<GeneratorForm onGenerate={ generate } onSave={ saveConfiguration }> <GeneratorForm onGenerate={ generate } onSave={ saveConfiguration }>
<fui.Field label={ i18n.t("advanced.password.length") }> <fui.Field label={ i18n.t("advanced.password.length") }>
<fui.Input value={ state.length?.toString() ?? "" } onChange={ setLength } /> <fui.Input value={ state.length?.toString() ?? "" } onChange={ setLength } onBlur={ updateLength } />
</fui.Field> </fui.Field>
<fui.Table size="small" as="div"> <fui.Table size="small" as="div">
<fui.TableHeader as="div"> <fui.TableHeader as="div">
@@ -95,19 +130,19 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
<fui.TableBody as="div"> <fui.TableBody as="div">
<Row> <Row>
<fui.Checkbox label={ i18n.t("common.characters.uppercase") } { ...checkboxControls("enableUppercase") } /> <fui.Checkbox label={ i18n.t("common.characters.uppercase") } { ...checkboxControls("enableUppercase") } />
<fui.Input { ...minInputControls("enableUppercase", "uppercaseCount") } /> <fui.Input { ...minInputControls("enableUppercase", "uppercaseCount") } onBlur={ updateLength } />
</Row> </Row>
<Row> <Row>
<fui.Checkbox label={ i18n.t("common.characters.lowercase") } { ...checkboxControls("enableLowercase") } /> <fui.Checkbox label={ i18n.t("common.characters.lowercase") } { ...checkboxControls("enableLowercase") } />
<fui.Input { ...minInputControls("enableLowercase", "lowercaseCount") } /> <fui.Input { ...minInputControls("enableLowercase", "lowercaseCount") } onBlur={ updateLength } />
</Row> </Row>
<Row> <Row>
<fui.Checkbox label={ i18n.t("common.characters.numeric") } { ...checkboxControls("enableNumeric") } /> <fui.Checkbox label={ i18n.t("common.characters.numeric") } { ...checkboxControls("enableNumeric") } />
<fui.Input { ...minInputControls("enableNumeric", "numericCount") } /> <fui.Input { ...minInputControls("enableNumeric", "numericCount") } onBlur={ updateLength } />
</Row> </Row>
<Row> <Row>
<fui.Checkbox label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special) } { ...checkboxControls("enableSpecial") } /> <fui.Checkbox label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special, true) } { ...checkboxControls("enableSpecial") } />
<fui.Input { ...minInputControls("enableSpecial", "specialCount") } /> <fui.Input { ...minInputControls("enableSpecial", "specialCount") } onBlur={ updateLength } />
</Row> </Row>
<Row> <Row>
<> <>
@@ -116,7 +151,7 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
placeholder={ i18n.t("common.characters.custom") } placeholder={ i18n.t("common.characters.custom") }
value={ state.customSet } onChange={ (_, e) => setState({ customSet: e.value }) } /> value={ state.customSet } onChange={ (_, e) => setState({ customSet: e.value }) } />
</> </>
<fui.Input { ...minInputControls("enableCustom", "customCount") } /> <fui.Input { ...minInputControls("enableCustom", "customCount") } onBlur={ updateLength } />
</Row> </Row>
</fui.TableBody> </fui.TableBody>
</fui.Table> </fui.Table>
@@ -133,13 +168,34 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
value={ state.excludeCustomSet } onChange={ (_, e) => setState({ excludeCustomSet: e.value }) } /> value={ state.excludeCustomSet } onChange={ (_, e) => setState({ excludeCustomSet: e.value }) } />
</div> </div>
</section> </section>
<div>
<fui.Checkbox
{ ...checkboxControls("enableSeparator") }
label={
<span className={ cls.separatorLabel }>
{ i18n.t("advanced.password.separator1") }
<fui.Input size="small" className={ cls.separatorInput }
disabled={ !state.enableSeparator }
value={ state.separator ?? "" }
onChange={ (_, e) => setState({ separator: e.value ? e.value[e.value.length - 1] : undefined }) } />
{ i18n.t("advanced.password.separator2") }
<fui.Input size="small" className={ cls.separatorInput }
disabled={ !state.enableSeparator }
value={ state.separatorInterval?.toString() ?? "" }
onBlur={ () => state.separatorInterval ? null : setState({ separatorInterval: DEFAULT_PASSWORD_LENGTH / 2 }) }
onChange={ setSeparatorInterval } />
{ i18n.t("advanced.password.separator3") }
</span>
} />
</div>
</GeneratorForm> </GeneratorForm>
); );
} }
function parseCount(value: string): number | null function parseCount(value: string): number | null
{ {
const n = parseInt(value); const n = parseInt(value, 10);
return isNaN(n) || n < 1 ? null : Math.min(n, 100); return isNaN(n) || n < 1 ? null : Math.min(n, 100);
}; };
@@ -162,6 +218,17 @@ const useStyles = fui.makeStyles({
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
}, },
separatorLabel:
{
display: "inline-flex",
flexWrap: "wrap",
alignItems: "center",
gap: `${fui.tokens.spacingVerticalXXS} ${fui.tokens.spacingHorizontalS}`,
},
separatorInput:
{
width: "4em",
}
}); });
type PasswordSectionState = type PasswordSectionState =
@@ -185,4 +252,8 @@ type PasswordSectionState =
excludeCustomSet: string; excludeCustomSet: string;
customSet: string; customSet: string;
enableSeparator: boolean;
separator?: string;
separatorInterval?: number;
}; };
+31 -2
View File
@@ -5,6 +5,7 @@ import { ArrowUndoRegular } from "@fluentui/react-icons";
import { ReactElement } from "react"; import { ReactElement } from "react";
import infoLabel from "../../utils/infoLabel"; import infoLabel from "../../utils/infoLabel";
import { useStyles } from "./SettingsSection.styles"; import { useStyles } from "./SettingsSection.styles";
import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from "@/utils/constants";
export default function SettingsSection(): ReactElement export default function SettingsSection(): ReactElement
{ {
@@ -28,7 +29,7 @@ export default function SettingsSection(): ReactElement
{ {
if (e.value.length >= 1) if (e.value.length >= 1)
{ {
const value = parseInt(e.value); const value = parseInt(e.value, 10);
if (!isNaN(value) && value >= 0) if (!isNaN(value) && value >= 0)
updateStorage({ [key]: value }); updateStorage({ [key]: value });
@@ -37,12 +38,38 @@ export default function SettingsSection(): ReactElement
updateStorage({ [key]: defaultValue }); updateStorage({ [key]: defaultValue });
}; };
const validateMinLimit = () =>
{
if (extOptions.MinLength < MIN_PASSWORD_LENGTH)
updateStorage({ MinLength: MIN_PASSWORD_LENGTH });
else if (extOptions.MinLength > MAX_PASSWORD_LENGTH - 1)
updateStorage({ MinLength: MAX_PASSWORD_LENGTH - 1, MaxLength: MAX_PASSWORD_LENGTH });
else if (extOptions.MinLength >= extOptions.MaxLength)
updateStorage({ MaxLength: extOptions.MinLength + 1 });
};
const validateMaxLimit = () =>
{
if (extOptions.MaxLength > MAX_PASSWORD_LENGTH)
updateStorage({ MaxLength: MAX_PASSWORD_LENGTH });
else if (extOptions.MaxLength < MIN_PASSWORD_LENGTH + 1)
updateStorage({ MinLength: MIN_PASSWORD_LENGTH, MaxLength: MIN_PASSWORD_LENGTH + 1 });
else if (extOptions.MaxLength <= extOptions.MinLength)
updateStorage({ MinLength: extOptions.MaxLength - 1 });
};
const validateLength = () =>
{
updateStorage({ Length: Math.max(Math.min(generatorOptions.Length, extOptions.MaxLength), extOptions.MinLength) });
};
return ( return (
<section className={ cls.root }> <section className={ cls.root }>
<fui.Field label={ i18n.t("settings.length.title") } hint={ i18n.t("settings.length.hint") }> <fui.Field label={ i18n.t("settings.length.title") } hint={ i18n.t("settings.length.hint") }>
<fui.Input <fui.Input
value={ generatorOptions.Length.toString() } value={ generatorOptions.Length.toString() }
onBlur={ validateLength }
onChange={ updateNumberField("Length", 0) } /> onChange={ updateNumberField("Length", 0) } />
</fui.Field> </fui.Field>
@@ -51,6 +78,7 @@ export default function SettingsSection(): ReactElement
<fui.Input <fui.Input
input={ { className: cls.rangeInput } } input={ { className: cls.rangeInput } }
value={ extOptions.MinLength.toString() } value={ extOptions.MinLength.toString() }
onBlur={ validateMinLimit }
onChange={ updateNumberField("MinLength", defaultOptions.extension.MinLength) } /> onChange={ updateNumberField("MinLength", defaultOptions.extension.MinLength) } />
<fui.Divider /> <fui.Divider />
@@ -58,6 +86,7 @@ export default function SettingsSection(): ReactElement
<fui.Input <fui.Input
input={ { className: cls.rangeInput } } input={ { className: cls.rangeInput } }
value={ extOptions.MaxLength.toString() } value={ extOptions.MaxLength.toString() }
onBlur={ validateMaxLimit }
onChange={ updateNumberField("MaxLength", defaultOptions.extension.MaxLength) } /> onChange={ updateNumberField("MaxLength", defaultOptions.extension.MaxLength) } />
<fui.Tooltip relationship="label" content={ i18n.t("common.actions.reset") }> <fui.Tooltip relationship="label" content={ i18n.t("common.actions.reset") }>
@@ -84,7 +113,7 @@ export default function SettingsSection(): ReactElement
checked={ generatorOptions.Numeric } checked={ generatorOptions.Numeric }
onChange={ setOption("Numeric") } /> onChange={ setOption("Numeric") } />
<fui.Checkbox <fui.Checkbox
label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special) } label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special, true) }
checked={ generatorOptions.Special } checked={ generatorOptions.Special }
onChange={ setOption("Special") } /> onChange={ setOption("Special") } />
<div> <div>
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "Password generator" title: "Password generator"
length: "Password length" length: "Password length"
min_of_type: "Minimum number of characters" min_of_type: "Minimum number of characters"
separator1: "Add separator"
separator2: "every"
separator3: "character(s)"
passphrase: passphrase:
title: "Passphrase generator" title: "Passphrase generator"
length: "Number of words" length: "Number of words"
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "Generator haseł" title: "Generator haseł"
length: "Długość hasła" length: "Długość hasła"
min_of_type: "Minimum" min_of_type: "Minimum"
separator1: "Dodaj separator"
separator2: "co"
separator3: "znak(ów)"
passphrase: passphrase:
title: "Frazy hasłowe" title: "Frazy hasłowe"
length: "Liczba słów" length: "Liczba słów"
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "Gerador de senhas" title: "Gerador de senhas"
length: "Comprimento da senha" length: "Comprimento da senha"
min_of_type: "Número mínimo de caracteres" min_of_type: "Número mínimo de caracteres"
separator1: "Adicionar separador"
separator2: "a cada"
separator3: "caractere(s)"
passphrase: passphrase:
title: "Gerador de frases-senha" title: "Gerador de frases-senha"
length: "Número de palavras" length: "Número de palavras"
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "Генератор паролей" title: "Генератор паролей"
length: "Длина пароля" length: "Длина пароля"
min_of_type: "Не менее" min_of_type: "Не менее"
separator1: "Добавить разделитель"
separator2: "каждые"
separator3: "символов"
passphrase: passphrase:
title: "Парольных фраз" title: "Парольных фраз"
length: "Количество слов" length: "Количество слов"
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "Генератор паролів" title: "Генератор паролів"
length: "Довжина пароля" length: "Довжина пароля"
min_of_type: "Не менше" min_of_type: "Не менше"
separator1: "Додати розділювач"
separator2: "кожні"
separator3: "символів"
passphrase: passphrase:
title: "Парольних фраз" title: "Парольних фраз"
length: "Кількість слів" length: "Кількість слів"
+3
View File
@@ -69,6 +69,9 @@ advanced:
title: "密码生成器" title: "密码生成器"
length: "密码长度" length: "密码长度"
min_of_type: "最少字符数" min_of_type: "最少字符数"
separator1: "添加分隔符"
separator2: "每"
separator3: "个字符"
passphrase: passphrase:
title: "密码短语生成器" title: "密码短语生成器"
length: "单词数量" length: "单词数量"
+808 -871
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,6 +1,6 @@
{ {
"name": "password-generator", "name": "password-generator",
"version": "5.0.5", "version": "5.1.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -15,21 +15,21 @@
"postinstall": "wxt prepare" "postinstall": "wxt prepare"
}, },
"dependencies": { "dependencies": {
"@fluentui/react-components": "^9.64.0", "@fluentui/react-components": "^9.66.5",
"@fluentui/react-icons": "^2.0.302", "@fluentui/react-icons": "^2.0.305",
"@wxt-dev/i18n": "^0.2.4", "@wxt-dev/i18n": "^0.2.4",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-responsive": "^10.0.1" "react-responsive": "^10.0.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.28.0", "@eslint/js": "^9.30.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.33.1", "@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.33.0", "@typescript-eslint/parser": "^8.35.1",
"@wxt-dev/module-react": "^1.1.3", "@wxt-dev/module-react": "^1.1.3",
"eslint": "^9.28.0", "eslint": "^9.30.0",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"globals": "^16.2.0", "globals": "^16.2.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
+3
View File
@@ -0,0 +1,3 @@
export const MIN_PASSWORD_LENGTH = 4;
export const MAX_PASSWORD_LENGTH = 512;
export const DEFAULT_PASSWORD_LENGTH = 8;
+21 -1
View File
@@ -1,3 +1,4 @@
import { MIN_PASSWORD_LENGTH } from "../constants";
import { pickRandomFromArray, shuffleString } from "./randomUtils"; import { pickRandomFromArray, shuffleString } from "./randomUtils";
const Characters = const Characters =
@@ -37,6 +38,10 @@ export function generatePassword(options: PasswordProps): string
} }
password = shuffleString(password); password = shuffleString(password);
if (options.separator && options.separatorInterval)
password = addSeparator(password, options.separator, options.separatorInterval);
return password; return password;
} }
@@ -47,7 +52,7 @@ export function generatePassword(options: PasswordProps): string
*/ */
export function validateOptions(options: PasswordProps): void export function validateOptions(options: PasswordProps): void
{ {
if (options.length < 4) if (options.length < MIN_PASSWORD_LENGTH)
throw new Error(i18n.t("errors.too_short")); throw new Error(i18n.t("errors.too_short"));
const availableCharacters: string = getAvailableCharacters(options); const availableCharacters: string = getAvailableCharacters(options);
@@ -122,6 +127,18 @@ function getRequiredCharacters(options: PasswordProps): string
return result; 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 = export type PasswordProps =
{ {
length: number; length: number;
@@ -139,4 +156,7 @@ export type PasswordProps =
excludeRepeating: boolean; excludeRepeating: boolean;
excludeCustom: string; excludeCustom: string;
separator?: string;
separatorInterval?: number;
}; };
+12 -7
View File
@@ -1,15 +1,20 @@
import { InfoLabel, Label, LabelProps, Slot } from "@fluentui/react-components"; import { InfoLabel, Label, LabelProps, makeStyles, Slot } from "@fluentui/react-components";
// FIXME: Remove ts-ignore comments once slots override fix is released export default function infoLabel(label: string, hint: string, noWrap?: boolean): Slot<typeof Label>
// Tracker: https://github.com/microsoft/fluentui/issues/27090
export default function infoLabel(label: string, hint: string): Slot<typeof Label>
{ {
// @ts-expect-error See FIXME const cls = useStyles();
return { return {
children: (_: unknown, props: LabelProps) => children: (_: unknown, props: LabelProps) =>
<InfoLabel { ...props } info={ hint }> <InfoLabel { ...props } info={ { className: noWrap ? cls.noWrap : undefined, children: hint } }>
{ label } { label }
</InfoLabel> </InfoLabel>
}; };
} }
const useStyles = makeStyles({
noWrap:
{
whiteSpace: "pre"
}
});
+3 -1
View File
@@ -1,5 +1,7 @@
import { MIN_PASSWORD_LENGTH } from "../constants";
export default class ExtensionOptions export default class ExtensionOptions
{ {
public MinLength: number = 4; public MinLength: number = MIN_PASSWORD_LENGTH;
public MaxLength: number = 32; public MaxLength: number = 32;
} }
+3 -1
View File
@@ -1,6 +1,8 @@
import { DEFAULT_PASSWORD_LENGTH } from "../constants";
export default class GeneratorOptions export default class GeneratorOptions
{ {
public Length: number = 8; public Length: number = DEFAULT_PASSWORD_LENGTH;
public Special: boolean = true; public Special: boolean = true;
public Numeric: boolean = true; public Numeric: boolean = true;