mirror of
https://github.com/XFox111/PasswordGeneratorExtension.git
synced 2026-07-02 19:52:43 +03:00
Compare commits
18 Commits
v2.0-4c266963
...
v2.2.6
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e4e49e0db | |||
| 4a11ebbb45 | |||
| 86c4e0498b | |||
| c7869010b6 | |||
| 6f9c13587d | |||
| 5d4088dd1a | |||
| 917884b883 | |||
| 33b3df7433 | |||
| 408d417c3f | |||
| f8a80d4a4c | |||
| 32bcdef7ec | |||
| 68aace475e | |||
| 4f578da227 | |||
| 5c49fc6b97 | |||
| 9ade276977 | |||
| ed9ae670d8 | |||
| 3f38322056 | |||
| 5e4a9f1699 |
@@ -3,7 +3,7 @@ name: Bug report
|
||||
about: Create a report to help us improve the extension
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: @XFox111
|
||||
assignees: xfox111
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: @XFox111
|
||||
assignees: xfox111
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
|
||||
@@ -10,20 +10,22 @@ updates:
|
||||
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
target-branch: "main"
|
||||
target-branch: "next"
|
||||
assignees:
|
||||
- "xfox111"
|
||||
reviewers:
|
||||
- "xfox111"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: monthly
|
||||
rebase-strategy: disabled
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "main"
|
||||
target-branch: "next"
|
||||
assignees:
|
||||
- "xfox111"
|
||||
reviewers:
|
||||
- "xfox111"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: monthly
|
||||
rebase-strategy: disabled
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
## Description
|
||||
> Put short description of the pull request here
|
||||
<!--Put short description of the pull request here-->
|
||||
|
||||
fixes: #issue_number
|
||||
Resolves: #issue_number
|
||||
|
||||
<!-- ------------------------------------- -->
|
||||
<!-- FOR REPOSITORY MAINTAINERS' PRS ONLY! -->
|
||||
<!-- DO NOT INCLUDE FOLLOWING IN YOUR PR!! -->
|
||||
<!-- ------------------------------------- -->
|
||||
|
||||
<!-- > ## 🚀 Patch Tuesday update
|
||||
> This pull request is a part of our new initiative!
|
||||
From now on we are starting to roll out updates on every first Tuesday of the month, which will include bugfixes, security and dependency updates to keep the project's security and stability up to date!
|
||||
|
||||
## Description
|
||||
Dependencies update and security fixes
|
||||
|
||||
## Changelog
|
||||
- Item 1
|
||||
- Item 2
|
||||
- Item 3
|
||||
### Dependencies bump
|
||||
- #
|
||||
### Fixed security vulnerabilities
|
||||
-
|
||||
|
||||
## PR Checklist (main branch)
|
||||
## PR Checklist
|
||||
- [ ] Update extension version in `package.json`
|
||||
- [ ] Create a release draft
|
||||
- [ ] [Post-merge] Create a release to publish the new version
|
||||
- [ ] [Post-deploy] Update changelog for Firefox webstore
|
||||
-->
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
<!-->> ## 🚀 Patch Tuesday update
|
||||
> This release is a part of our new initiative!
|
||||
From now on we are starting to roll out updates on every first Tuesday of the month, which will include bugfixes, security and dependency updates to keep the project's security and stability up to date!
|
||||
-->
|
||||
## What's new
|
||||
-
|
||||
<!-- - Dependency updates and security patches -->
|
||||
|
||||
## Installation
|
||||
### From extension webstore (recommended)
|
||||
- [Google Chrome Webstore](https://chrome.google.com/webstore/detail/jnjobgjobffgmgfnkpkjfjkkfhfikmfl)
|
||||
- [Microsoft Edge Add-ons Webstore](https://microsoftedge.microsoft.com/addons/detail/manimdhobjbkfpeeehlhhneookiokpbj)
|
||||
- [Firefox Add-ons](https://addons.mozilla.org/en-US/firefox/addon/easy-password-generator/)
|
||||
- [GitHub Releases](https://github.com/xfox111/PasswordGeneratorExtension/releases/latest)
|
||||
<!-->### Fixed security issues in this update
|
||||
- [CWE-20](https://cwe.mitre.org/data/definitions/20.html)
|
||||
- CVE-2022-25883
|
||||
-->
|
||||
|
||||
Note that version published on these webstores can differ from this release
|
||||
### Sideloading (for testing purposes only)
|
||||
1. Download attached archive and unpack it
|
||||
2. Enable Developers mode on your browser extensions page
|
||||
3. Click "Load unpacked" button and navigate to the extension root folder (contains `manifest.json`)
|
||||
4. Done!
|
||||
|
||||
*On Firefox you should open manifest file instead of extension's folder
|
||||
|
||||
**Note:** If you delete extension folder it will disappear from your browser
|
||||
|
||||
_Sideloaded extensions don't replace officially installed ones_
|
||||
Refer to [Download section of README.md](https://github.com/XFox111/PasswordGeneratorExtension#download) for instructions and download links
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
name: Release pipeline
|
||||
|
||||
on:
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
types: [ released ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -23,9 +22,9 @@ jobs:
|
||||
$manifest.version = $package.version;
|
||||
$manifest | ConvertTo-Json -Depth 10 | Out-File "public/manifest.json"
|
||||
|
||||
$manifest = Get-Content "public/manifest.firefox.json" | ConvertFrom-Json;
|
||||
$manifest = Get-Content "public/manifest.v2.json" | ConvertFrom-Json;
|
||||
$manifest.version = $package.version;
|
||||
$manifest | ConvertTo-Json -Depth 10 | Out-File "public/manifest.firefox.json"
|
||||
$manifest | ConvertTo-Json -Depth 10 | Out-File "public/manifest.v2.json"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
@@ -37,7 +36,7 @@ jobs:
|
||||
- run: yarn build
|
||||
|
||||
- name: Drop artifacts (build)
|
||||
uses: actions/upload-artifact@v3.1.0
|
||||
uses: actions/upload-artifact@v3.1.2
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
@@ -54,15 +53,15 @@ jobs:
|
||||
- name: Configure manifest
|
||||
uses: Amadevus/pwsh-script@v2
|
||||
with:
|
||||
script: Remove-Item "manifest.firefox.json"
|
||||
script: Remove-Item "manifest.v2.json"
|
||||
|
||||
- name: Pack extension
|
||||
uses: TheDoctor0/zip-release@0.6.2
|
||||
uses: TheDoctor0/zip-release@0.7.1
|
||||
with:
|
||||
filename: PasswordGenerator-Chromium.zip
|
||||
|
||||
- name: Drop artifacts (Chromium)
|
||||
uses: actions/upload-artifact@v3.1.0
|
||||
uses: actions/upload-artifact@v3.1.2
|
||||
with:
|
||||
name: Chromium
|
||||
path: PasswordGenerator-Chromium.zip
|
||||
@@ -90,15 +89,22 @@ jobs:
|
||||
with:
|
||||
script: |
|
||||
Remove-Item "manifest.json"
|
||||
Rename-Item "manifest.firefox.json" "manifest.json"
|
||||
Rename-Item "manifest.v2.json" "manifest.json"
|
||||
|
||||
- name: "web-ext lint"
|
||||
uses: kewisch/action-web-ext@e0ea88d527a8a90bc10d600f80ac667d219e6bf1
|
||||
with:
|
||||
cmd: lint
|
||||
source: .
|
||||
channel: listed
|
||||
|
||||
- name: Pack extension
|
||||
uses: TheDoctor0/zip-release@0.6.2
|
||||
uses: TheDoctor0/zip-release@0.7.1
|
||||
with:
|
||||
filename: PasswordGenerator-Firefox.zip
|
||||
|
||||
- name: Drop artifacts (Firefox)
|
||||
uses: actions/upload-artifact@v3.1.0
|
||||
uses: actions/upload-artifact@v3.1.2
|
||||
with:
|
||||
name: Firefox
|
||||
path: PasswordGenerator-Firefox.zip
|
||||
|
||||
@@ -13,7 +13,7 @@ name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: [ "main", "next" ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
@@ -23,7 +23,7 @@ on:
|
||||
- '**/pr_pipeline.yaml'
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "main" ]
|
||||
branches: [ "main", "next" ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
|
||||
@@ -2,8 +2,7 @@ name: PR check pipeline
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
branches: [ "main", "next" ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
@@ -20,17 +19,63 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Configure manifest
|
||||
uses: Amadevus/pwsh-script@v2
|
||||
with:
|
||||
script: |
|
||||
[PSCustomObject] $package = Get-Content "package.json" | ConvertFrom-Json;
|
||||
[PSCustomObject] $manifest = Get-Content "public/manifest.json" | ConvertFrom-Json;
|
||||
$manifest.version = $package.version;
|
||||
$manifest | ConvertTo-Json -Depth 10 | Out-File "public/manifest.json"
|
||||
$manifest = Get-Content "public/manifest.v2.json" | ConvertFrom-Json;
|
||||
$manifest.version = $package.version;
|
||||
$manifest | ConvertTo-Json -Depth 10 | Out-File "public/manifest.v2.json"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'yarn'
|
||||
cache: yarn
|
||||
|
||||
- run: yarn install
|
||||
- run: yarn build
|
||||
|
||||
- name: 'Drop artifacts'
|
||||
uses: actions/upload-artifact@v3
|
||||
- name: Drop artifacts (build)
|
||||
uses: actions/upload-artifact@v3.1.2
|
||||
with:
|
||||
name: 'Package'
|
||||
path: 'build'
|
||||
name: build
|
||||
path: build
|
||||
|
||||
firefox-check:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build
|
||||
|
||||
- name: Configure manifest
|
||||
uses: Amadevus/pwsh-script@v2
|
||||
with:
|
||||
script: |
|
||||
Remove-Item "manifest.json"
|
||||
Rename-Item "manifest.v2.json" "manifest.json"
|
||||
|
||||
- name: "web-ext lint"
|
||||
uses: kewisch/action-web-ext@e0ea88d527a8a90bc10d600f80ac667d219e6bf1
|
||||
with:
|
||||
cmd: lint
|
||||
source: .
|
||||
channel: listed
|
||||
|
||||
- name: Pack extension
|
||||
uses: TheDoctor0/zip-release@0.7.1
|
||||
with:
|
||||
filename: PasswordGenerator-Firefox.zip
|
||||
|
||||
- name: Drop artifacts (Firefox)
|
||||
uses: actions/upload-artifact@v3.1.2
|
||||
with:
|
||||
name: Firefox
|
||||
path: PasswordGenerator-Firefox.zip
|
||||
|
||||
+94
-16
@@ -112,7 +112,7 @@ This section represents how contributors should interact with codebase implement
|
||||
7. Done
|
||||
|
||||
#### Release
|
||||
Next stage is release. Release performs on every push to main (which makes functional changes to the source code). Release performs manually by @XFox111 into: Chrome webstore, Edge webstore and GitHub releases
|
||||
Next stage is release. Release performs on every push to main (which makes functional changes to the source code). Release performs manually by @XFox111 into: Chrome, Firefox, Edge webstores as well as GitHub releases
|
||||
|
||||
### Coding guidelines
|
||||
#### Indentation
|
||||
@@ -121,7 +121,8 @@ We use tabs, not spaces.
|
||||
#### Names
|
||||
The project naming rules inherit [.NET Naming Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines). Nevertheless there'is some distinction with the guidelines as well as additions to the one:
|
||||
- Use `camelCase` for variables instead of `CamelCase` stated in [Capitalization Conventions](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions#capitalization-rules-for-identifiers)
|
||||
- Use `snake_case` for file names
|
||||
- Use `camelCase` for files in `public` directory
|
||||
- Use `PascalCase` for files in `src` directory
|
||||
|
||||
#### Comments
|
||||
Leave as more comments as you can. Remember: the more detailed documentation your code has the less programmers will curse you in the future
|
||||
@@ -131,43 +132,48 @@ Use "double quotes" wherever it's possible
|
||||
|
||||
#### Style
|
||||
- Prefer to use lambda functions
|
||||
- Put curly braces on new lines
|
||||
- Always put curly braces on new lines
|
||||
- Wrong:
|
||||
```
|
||||
```js
|
||||
if (condition) {
|
||||
...
|
||||
}
|
||||
```
|
||||
- Correct:
|
||||
```
|
||||
```js
|
||||
if (condition)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
- Put spaces between operators and before braces in methods declarations, conditionals and loops
|
||||
> **Note:** For JSON files put opening brace on the same line as the key
|
||||
- Put spaces between operators, conditionals and loops
|
||||
- Wrong:
|
||||
- `y=k*x+b`
|
||||
- `function FunctionName()`
|
||||
```js
|
||||
y=k*x+b;
|
||||
if(condition) { ... }
|
||||
```
|
||||
- Correct:
|
||||
- `y = k * x + b`
|
||||
- `function FunctionName ()`
|
||||
- Use ternary conditionals wherever it's possible
|
||||
```js
|
||||
y = k * x + b;
|
||||
if (condition) { ... }
|
||||
```
|
||||
- Use ternary conditionals wherever it's possible, unless it's too long
|
||||
- Wrong:
|
||||
```
|
||||
```js
|
||||
var s;
|
||||
if (condition)
|
||||
s = "Life";
|
||||
else
|
||||
s = "Death"
|
||||
s = "Death";
|
||||
```
|
||||
- Correct:
|
||||
```
|
||||
```js
|
||||
var s = condition ? "Life" : "Death";
|
||||
```
|
||||
- Do not surround loop and conditional bodies with curly braces if they can be avoided
|
||||
- Wrong:
|
||||
```
|
||||
```js
|
||||
if (condition)
|
||||
{
|
||||
console.log("Hello, World!");
|
||||
@@ -178,12 +184,84 @@ Use "double quotes" wherever it's possible
|
||||
}
|
||||
```
|
||||
- Correct
|
||||
```
|
||||
```js
|
||||
if (condition)
|
||||
console.log("Hello, World!");
|
||||
else
|
||||
return;
|
||||
```
|
||||
- Prefer export modules as default
|
||||
- Wrong:
|
||||
```js
|
||||
export class MyClass { ... }
|
||||
```
|
||||
- Correct:
|
||||
```js
|
||||
export default class MyClass { ... }
|
||||
```
|
||||
- Prefer export modules as classes unless it is excessive
|
||||
- Wrong:
|
||||
```ts
|
||||
export function MyFunction1() { ... }
|
||||
export function MyFunction2() { ... }
|
||||
export default class MyClass2()
|
||||
{
|
||||
public static GetDate(timestamp: number): Date
|
||||
{
|
||||
return new Date(timestamp);
|
||||
}
|
||||
}
|
||||
```
|
||||
- Correct:
|
||||
```js
|
||||
export default class MyClass1
|
||||
{
|
||||
public static MyFunction1() { ... }
|
||||
public static MyFunction2() { ... }
|
||||
}
|
||||
export default GetDate(timestamp: number): Date
|
||||
{
|
||||
return new Date(timestamp);
|
||||
}
|
||||
```
|
||||
- When JSX attributes take too much space, put each attribute on a new line and put additional line before component's content
|
||||
- Wrong:
|
||||
```tsx
|
||||
<HelloWorld attribute1="value" attribute2={ value } attribute3="value">My content here</HelloWorld>
|
||||
<HelloWorld attribute1="value"
|
||||
attribute2={ value }
|
||||
attribute3="value">My content here</HelloWorld>
|
||||
<HelloWorld attribute1="value"
|
||||
attribute2={ value }
|
||||
attribute3="value">
|
||||
My content here
|
||||
</HelloWorld>
|
||||
<HelloWorld
|
||||
attribute1="value"
|
||||
attribute2={ value }
|
||||
attribute3="value">
|
||||
My content here
|
||||
</HelloWorld>
|
||||
```
|
||||
- Correct:
|
||||
```tsx
|
||||
<HelloWorld
|
||||
attribute1="value"
|
||||
attribute2={ value }
|
||||
attribute3="value">
|
||||
|
||||
My content here
|
||||
</HelloWorld>
|
||||
```
|
||||
- If JSX component doesn't have content, put space before closing tag
|
||||
- Wrong:
|
||||
```tsx
|
||||
<HelloWorld attribute1="value" attribute2={ value } attribute3="value"/>
|
||||
```
|
||||
- Correct:
|
||||
```tsx
|
||||
<HelloWorld attribute1="value" attribute2={ value } attribute3="value" />
|
||||
```
|
||||
|
||||
### Finding an issue to work on
|
||||
Check out the [full issues list](https://github.com/XFox111/PasswordGeneratorExtension/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue) for a list of all potential areas for contributions. **Note** that just because an issue exists in the repository does not mean we will accept a contribution. There are several reasons we may not accept a pull request like:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Password generator
|
||||
[](https://github.com/xfox111/PasswordGeneratorExtension/releases/latest)
|
||||
[](https://github.com/xfox111/PasswordGeneratorExtension/commits/master)
|
||||
[](https://github.com/XFox111/PasswordGeneratorExtension/commits/main)
|
||||
|
||||
[](https://twitter.com/xfox111)
|
||||
[](https://github.com/xfox111)
|
||||
@@ -16,21 +16,66 @@ Extension for web browsers which helps you to easily generate strong passwords i
|
||||
- Clean and simple UI
|
||||
- Dark mode
|
||||
|
||||
## Languages
|
||||
- English
|
||||
- Ukrainian
|
||||
- Polish
|
||||
- Russian
|
||||
- Portuguese (Brazil)
|
||||
|
||||
<img width="1136" alt="Password generator v2.0" src="https://user-images.githubusercontent.com/28831743/188680034-a673b1b4-3153-4054-bb0d-949568de1748.png">
|
||||
|
||||
## Download
|
||||
[](https://chrome.google.com/webstore/detail/jnjobgjobffgmgfnkpkjfjkkfhfikmfl)
|
||||
[](https://addons.mozilla.org/firefox/addon/easy-password-generator/)
|
||||
[](https://addons.mozilla.org/firefox/addon/easy-password-generator/)
|
||||
|
||||
- [Google Chrome Webstore](https://chrome.google.com/webstore/detail/jnjobgjobffgmgfnkpkjfjkkfhfikmfl)
|
||||
- [Microsoft Edge Add-ons Webstore](https://microsoftedge.microsoft.com/addons/detail/manimdhobjbkfpeeehlhhneookiokpbj)
|
||||
- [Firefox Add-ons](https://addons.mozilla.org/en-US/firefox/addon/easy-password-generator/)
|
||||
- [GitHub Releases](https://github.com/xfox111/PasswordGeneratorExtension/releases/latest)
|
||||
|
||||
### Sideloading (for testing purposes only)
|
||||
|
||||
<details>
|
||||
<summary>Click to expand</summary>
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary><b>Chromium-based browsers (Edge, Chrome, etc.)</b></summary>
|
||||
|
||||
> 1. Go to [Releases](https://github.com/XFox111/PasswordGeneratorExtension/releases) and select a release to download
|
||||
> 2. Download attached archive for Chromium and unpack it
|
||||
> 3. Go to "chrome://extensions"
|
||||
> 4. Enable "Developer mode"
|
||||
> 5. Click the "Load unpacked" button and navigate to the extension's root folder (contains `manifest.json`)
|
||||
> 6. Done!
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Firefox</b></summary>
|
||||
|
||||
> 1. Go to [Releases](https://github.com/XFox111/PasswordGeneratorExtension/releases) and select a release to download
|
||||
> 2. Download attached archive for Firefox and unpack it
|
||||
> 3. Go to "about:debugging#/runtime/this-firefox"
|
||||
> 4. Click the "Load Temporary Add-on..." button and select `manifest.josn` file in the root folder
|
||||
> 5. Done!
|
||||
|
||||
> **Important!**
|
||||
This will _replace_ officialy installed version if you have one.
|
||||
If you want to sideload it without replacing to run both versions at the same time - before loading add-on, open `manifest.json` in a text editor and change `id` key (it's `passwordgenerator@xfox111.net` by default) to something else
|
||||
|
||||
</details>
|
||||
|
||||
> **Note:** If you delete the extension folder it will disappear from your browser
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
## Contributing
|
||||
[](https://github.com/xfox111/PasswordGeneratorExtension/issues)
|
||||

|
||||
[](https://github.com/XFox111/PasswordGeneratorExtension/actions/workflows/cd_pipeline.yaml)
|
||||
[](https://github.com/xfox111/PasswordGeneratorExtension)
|
||||
|
||||
There are many ways in which you can participate in the project, for example:
|
||||
@@ -50,6 +95,6 @@ If you are interested in fixing issues and contributing directly to the code bas
|
||||
This project has adopted the Contributor Covenant. For more information see the [Code of Conduct](https://github.com/XFox111/PasswordGeneratorExtension/blob/master/CODE_OF_CONDUCT.md)
|
||||
|
||||
## Copyrights
|
||||
> ©2022 Eugene Fox
|
||||
> ©2023 Eugene Fox
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
+1
-1
@@ -18,4 +18,4 @@ If you are willing to continue using 1.x version, you can sideload it from the [
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
In case you find a security issue, please report it to us by [creating an issue](https://github.com/XFox111/PasswordGeneratorExtension/issues/new?assignees=xfox111&labels=bug&template=bug_report.md&title=)
|
||||
In case you find a security issue, please report it to us by [creating an issue](https://github.com/XFox111/PasswordGeneratorExtension/issues/new?assignees=xfox111&labels=security+vulnerability&template=bug_report.md&title=)
|
||||
|
||||
+51
-19
@@ -1,35 +1,67 @@
|
||||
import { CracoConfig, WebpackContext } from "@craco/types";
|
||||
import { Configuration as WebpackConfig } from "webpack";
|
||||
import HtmlWebapckPlugin, { MinifyOptions } from "html-webpack-plugin";
|
||||
import { Configuration } from "webpack";
|
||||
|
||||
// Craco config file
|
||||
// Craco is used to separate content and background scripts from the main JS bundle
|
||||
|
||||
export default
|
||||
const cracoConfig: CracoConfig =
|
||||
{
|
||||
webpack:
|
||||
{
|
||||
configure: (webpackConfig : any, { env, paths } : IEnvironment) =>
|
||||
configure: ((webpackConfig: WebpackConfig, { env, paths }: WebpackContext): WebpackConfig =>
|
||||
{
|
||||
return {
|
||||
const isProduction: boolean = env === "production";
|
||||
|
||||
const config: WebpackConfig =
|
||||
{
|
||||
...webpackConfig,
|
||||
entry:
|
||||
{
|
||||
main: [ env === "development" && require.resolve("react-dev-utils/webpackHotDevClient"), paths.appIndexJs ].filter(Boolean),
|
||||
main: paths!.appIndexJs,
|
||||
background: "./src/Services/BackgroundService.ts",
|
||||
contentScript: "./src/Services/ContentService.ts"
|
||||
contentScript: "./src/Services/ContentService.ts",
|
||||
},
|
||||
output:
|
||||
{
|
||||
...webpackConfig.output,
|
||||
filename: "static/js/[name].js",
|
||||
filename: "static/js/[name].js"
|
||||
},
|
||||
optimization:
|
||||
{
|
||||
...webpackConfig.optimization,
|
||||
splitChunks: { cacheGroups: { default: false } },
|
||||
runtimeChunk: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interface IEnvironment
|
||||
{
|
||||
env: string;
|
||||
paths:
|
||||
{
|
||||
[key: string]: string | string[]
|
||||
};
|
||||
}
|
||||
const minifyOptions: MinifyOptions =
|
||||
{
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true
|
||||
};
|
||||
|
||||
config.plugins = config.plugins?.filter((plugin: any) => plugin.constructor.name !== "HtmlWebpackPlugin") ?? [];
|
||||
|
||||
config.plugins.push(new HtmlWebapckPlugin({
|
||||
inject: true,
|
||||
chunks: ["main"],
|
||||
template: paths!.appHtml,
|
||||
filename: "index.html",
|
||||
minify: isProduction && minifyOptions
|
||||
}));
|
||||
|
||||
return config;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
export default cracoConfig;
|
||||
|
||||
+35
-31
@@ -1,57 +1,61 @@
|
||||
{
|
||||
"name": "password-generator",
|
||||
"version": "2.0.0",
|
||||
"version": "2.2.6",
|
||||
"private": true,
|
||||
"dependencies":
|
||||
{
|
||||
"@craco/craco": "^6.4.5",
|
||||
"@fluentui/react-components": "^9.2.0",
|
||||
"@fluentui/react-icons": "^2.0.179",
|
||||
"dependencies": {
|
||||
"@craco/craco": "^7.1.0",
|
||||
"@fluentui/react-components": "^9.19.1",
|
||||
"@fluentui/react-icons": "^2.0.199",
|
||||
"react": "^18.2.0",
|
||||
"react-device-detect": "^2.2.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.54.8",
|
||||
"typescript": "^4.8.2"
|
||||
"sass": "^1.63.6",
|
||||
"typescript": "^5.1.6",
|
||||
"webextension-polyfill": "^0.10.0"
|
||||
},
|
||||
"devDependencies":
|
||||
{
|
||||
"devDependencies": {
|
||||
"@craco/types": "^7.1.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/chrome": "^0.0.195",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^18.7.15",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"react-scripts": "5.0.1"
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/react": "^18.2.14",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"@types/webextension-polyfill": "^0.10.1",
|
||||
"html-webpack-plugin": "^5.5.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"webpack": "^5.88.1"
|
||||
},
|
||||
"scripts":
|
||||
{
|
||||
"start": "react-scripts start",
|
||||
"build": "INLINE_RUNTIME_CHUNK=false craco build",
|
||||
"scripts": {
|
||||
"start": "craco start",
|
||||
"build": "craco build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig":
|
||||
{
|
||||
"extends":
|
||||
[
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist":
|
||||
{
|
||||
"production":
|
||||
[
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development":
|
||||
[
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"json5": "1.0.2",
|
||||
"loader-utils": "2.0.4",
|
||||
"minimatch": "3.0.5",
|
||||
"nth-check": "2.0.1",
|
||||
"semver": "^7.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,216 +1,173 @@
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"name": {
|
||||
"message": "Password Generator",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"description":
|
||||
{
|
||||
"description": {
|
||||
"message": "Password generator extension allows you to easily generate long and secure password in one click",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"author":
|
||||
{
|
||||
"author": {
|
||||
"message": "Eugene Fox",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"Password_generator":
|
||||
{
|
||||
"Password_generator": {
|
||||
"message": "Password generator",
|
||||
"description": "App.tsx"
|
||||
},
|
||||
"Copy":
|
||||
{
|
||||
"Copy": {
|
||||
"message": "Copy",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Generate_new":
|
||||
{
|
||||
"Generate_new": {
|
||||
"message": "Generate new",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Exclude_special_symbols_one_time":
|
||||
{
|
||||
"Exclude_special_symbols_one_time": {
|
||||
"message": "Generate password without special symbols",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Include_special_symbols_one_time":
|
||||
{
|
||||
"Include_special_symbols_one_time": {
|
||||
"message": "Generate password with special symbols",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Settings":
|
||||
{
|
||||
"Settings": {
|
||||
"message": "Settings",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Password_length":
|
||||
{
|
||||
"Password_length": {
|
||||
"message": "Password length",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Recommended_password_length":
|
||||
{
|
||||
"Recommended_password_length": {
|
||||
"message": "Recommended password length",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Character_options":
|
||||
{
|
||||
"Character_options": {
|
||||
"message": "Character options",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Include":
|
||||
{
|
||||
"Include": {
|
||||
"message": "Include",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Special_symbols":
|
||||
{
|
||||
"Special_symbols": {
|
||||
"message": "Special symbols",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Numeric":
|
||||
{
|
||||
"Numeric": {
|
||||
"message": "Numeric",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Uppercase":
|
||||
{
|
||||
"Uppercase": {
|
||||
"message": "Uppercase",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Lowercase":
|
||||
{
|
||||
"Lowercase": {
|
||||
"message": "Lowercase",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Exclude":
|
||||
{
|
||||
"Exclude": {
|
||||
"message": "Exclude",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Similar":
|
||||
{
|
||||
"Similar": {
|
||||
"message": "Similar",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Ambiguous":
|
||||
{
|
||||
"Ambiguous": {
|
||||
"message": "Ambiguous",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Repeating":
|
||||
{
|
||||
"Repeating": {
|
||||
"message": "Repeating",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Add_shortcut_to_context_menu":
|
||||
{
|
||||
"Add_shortcut_to_context_menu": {
|
||||
"message": "Add shortcut to context menu",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Right_click_password_field_to_quickly_generate_password":
|
||||
{
|
||||
"Right_click_password_field_to_quickly_generate_password": {
|
||||
"message": "Right-click password field to quickly generate password",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Automatically_copy_to_clipboard":
|
||||
{
|
||||
"Automatically_copy_to_clipboard": {
|
||||
"message": "Automatically copy to clipboard",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"About":
|
||||
{
|
||||
"About": {
|
||||
"message": "About",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Developed_by_Eugene_Fox":
|
||||
{
|
||||
"Developed_by_Eugene_Fox": {
|
||||
"message": "Developed by Eugene Fox",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Licensed_under":
|
||||
{
|
||||
"Licensed_under": {
|
||||
"message": "Licensed under",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"MIT_license":
|
||||
{
|
||||
"MIT_license": {
|
||||
"message": "MIT license",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Want_to_contribute_translation_for_your_language_":
|
||||
{
|
||||
"Want_to_contribute_translation_for_your_language_": {
|
||||
"message": "Want to contribute translation for your language?",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Read_this_to_get_started":
|
||||
{
|
||||
"Read_this_to_get_started": {
|
||||
"message": "Read this to get started",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"My_website":
|
||||
{
|
||||
"My_website": {
|
||||
"message": "My website",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Source_code":
|
||||
{
|
||||
"Source_code": {
|
||||
"message": "Source code",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Changelog":
|
||||
{
|
||||
"Changelog": {
|
||||
"message": "Changelog",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Leave_feedback":
|
||||
{
|
||||
"Leave_feedback": {
|
||||
"message": "Leave feedback",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Buy_me_a_coffee":
|
||||
{
|
||||
"Buy_me_a_coffee": {
|
||||
"message": "Buy me a coffee",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Set_name":
|
||||
{
|
||||
"Set_name": {
|
||||
"message": "Name",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Characters":
|
||||
{
|
||||
"Characters": {
|
||||
"message": "Characters",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"__etc_":
|
||||
{
|
||||
"__etc_": {
|
||||
"message": ", etc.",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"OK":
|
||||
{
|
||||
"OK": {
|
||||
"message": "OK",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included":
|
||||
{
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included": {
|
||||
"message": "Either lowercase or uppercase characters must be included",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters":
|
||||
{
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters": {
|
||||
"message": "Selected length is too long to exclude repeating characters",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Quick_generator_is_only_available_on_password_fields":
|
||||
{
|
||||
"Quick_generator_is_only_available_on_password_fields": {
|
||||
"message": "Quick generator is only available on password fields",
|
||||
"description": "ContentService.tsx"
|
||||
},
|
||||
"Quick_generate_password":
|
||||
{
|
||||
"Quick_generate_password": {
|
||||
"message": "Quick generate password",
|
||||
"description": "BackgroundService.tsx"
|
||||
}
|
||||
|
||||
@@ -1,216 +1,173 @@
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"name": {
|
||||
"message": "Generator haseł",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"description":
|
||||
{
|
||||
"description": {
|
||||
"message": "Rozszerzenie, które pozwala na łatwe generowanie trudnych i bezpiecznych haseł w jednym kliknięciu",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"author":
|
||||
{
|
||||
"author": {
|
||||
"message": "Jewgienij Lis",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"Password_generator":
|
||||
{
|
||||
"Password_generator": {
|
||||
"message": "Generator haseł",
|
||||
"description": "App.tsx"
|
||||
},
|
||||
"Copy":
|
||||
{
|
||||
"Copy": {
|
||||
"message": "Kopiuj",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Generate_new":
|
||||
{
|
||||
"Generate_new": {
|
||||
"message": "Utwórz nowy",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Exclude_special_symbols_one_time":
|
||||
{
|
||||
"Exclude_special_symbols_one_time": {
|
||||
"message": "Wygeneruj hasło bez znaków specjalnych",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Include_special_symbols_one_time":
|
||||
{
|
||||
"Include_special_symbols_one_time": {
|
||||
"message": "Wygeneruj hasło z znakami specjalnymi",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Settings":
|
||||
{
|
||||
"Settings": {
|
||||
"message": "Ustawienia",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Password_length":
|
||||
{
|
||||
"Password_length": {
|
||||
"message": "Długość hasła",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Recommended_password_length":
|
||||
{
|
||||
"Recommended_password_length": {
|
||||
"message": "Zalecana długość hasła",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Character_options":
|
||||
{
|
||||
"Character_options": {
|
||||
"message": "Ustawienia symboli",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Include":
|
||||
{
|
||||
"Include": {
|
||||
"message": "Włącz",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Special_symbols":
|
||||
{
|
||||
"Special_symbols": {
|
||||
"message": "Znaki specjalne",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Numeric":
|
||||
{
|
||||
"Numeric": {
|
||||
"message": "Liczby",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Uppercase":
|
||||
{
|
||||
"Uppercase": {
|
||||
"message": "Wielkie litery",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Lowercase":
|
||||
{
|
||||
"Lowercase": {
|
||||
"message": "Małe litery",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Exclude":
|
||||
{
|
||||
"Exclude": {
|
||||
"message": "Wyłącz",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Similar":
|
||||
{
|
||||
"Similar": {
|
||||
"message": "Podobne",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Ambiguous":
|
||||
{
|
||||
"Ambiguous": {
|
||||
"message": "Niebezpieczne",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Repeating":
|
||||
{
|
||||
"Repeating": {
|
||||
"message": "Powtarzające się",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Add_shortcut_to_context_menu":
|
||||
{
|
||||
"Add_shortcut_to_context_menu": {
|
||||
"message": "Dodaj rozszerzenie do menu kontekstowego",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Right_click_password_field_to_quickly_generate_password":
|
||||
{
|
||||
"Right_click_password_field_to_quickly_generate_password": {
|
||||
"message": "Kliknij prawym przyciskiem myszy w pole hasła, aby szybko wygenerować hasło",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Automatically_copy_to_clipboard":
|
||||
{
|
||||
"Automatically_copy_to_clipboard": {
|
||||
"message": "Automatycznie kopiuj do schowka",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"About":
|
||||
{
|
||||
"About": {
|
||||
"message": "O rozszerzeniu",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Developed_by_Eugene_Fox":
|
||||
{
|
||||
"Developed_by_Eugene_Fox": {
|
||||
"message": "Autor: Jewgienij Lis",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Licensed_under":
|
||||
{
|
||||
"Licensed_under": {
|
||||
"message": "Licencja",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"MIT_license":
|
||||
{
|
||||
"MIT_license": {
|
||||
"message": "MIT",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Want_to_contribute_translation_for_your_language_":
|
||||
{
|
||||
"Want_to_contribute_translation_for_your_language_": {
|
||||
"message": "Chcesz pomóc z tłumaczeniem na swój język?",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Read_this_to_get_started":
|
||||
{
|
||||
"Read_this_to_get_started": {
|
||||
"message": "Przeczytaj ten artykuł",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"My_website":
|
||||
{
|
||||
"My_website": {
|
||||
"message": "Moja strona internetowa",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Source_code":
|
||||
{
|
||||
"Source_code": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Changelog":
|
||||
{
|
||||
"Changelog": {
|
||||
"message": "Lista zmian",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Leave_feedback":
|
||||
{
|
||||
"Leave_feedback": {
|
||||
"message": "Zostaw opinię",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Buy_me_a_coffee":
|
||||
{
|
||||
"Buy_me_a_coffee": {
|
||||
"message": "Wesprzyj",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Set_name":
|
||||
{
|
||||
"Set_name": {
|
||||
"message": "Nazwa",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Characters":
|
||||
{
|
||||
"Characters": {
|
||||
"message": "Znaki",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"__etc_":
|
||||
{
|
||||
"__etc_": {
|
||||
"message": " itp.",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"OK":
|
||||
{
|
||||
"OK": {
|
||||
"message": "OK",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included":
|
||||
{
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included": {
|
||||
"message": "Muszą być uwzględnione małe lub wielkie litery",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters":
|
||||
{
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters": {
|
||||
"message": "Wybrana długość jest zbyt długa, aby wykluczyć powtarzające się znaki",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Quick_generator_is_only_available_on_password_fields":
|
||||
{
|
||||
"Quick_generator_is_only_available_on_password_fields": {
|
||||
"message": "Szybki generator jest dostępny tylko dla pól hasła",
|
||||
"description": "ContentService.tsx"
|
||||
},
|
||||
"Quick_generate_password":
|
||||
{
|
||||
"Quick_generate_password": {
|
||||
"message": "Wygeneruj hasło",
|
||||
"description": "BackgroundService.tsx"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"name": {
|
||||
"message": "Gerador de Senhas",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"description": {
|
||||
"message": "A extensão do gerador de senhas permite gerar facilmente uma senha longa e segura em um clique",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"author": {
|
||||
"message": "Eugene Fox",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"Password_generator": {
|
||||
"message": "Gerador de senhas",
|
||||
"description": "App.tsx"
|
||||
},
|
||||
"Copy": {
|
||||
"message": "Copiar",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Generate_new": {
|
||||
"message": "Gerar nova",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Exclude_special_symbols_one_time": {
|
||||
"message": "Gerar senha sem símbolos especiais",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Include_special_symbols_one_time": {
|
||||
"message": "Gerar senha com símbolos especiais",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Settings": {
|
||||
"message": "Configurações",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Password_length": {
|
||||
"message": "Comprimento da senha",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Recommended_password_length": {
|
||||
"message": "Comprimento recomendado da senha",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Character_options": {
|
||||
"message": "Opções de caracteres",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Include": {
|
||||
"message": "Incluir",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Special_symbols": {
|
||||
"message": "Símbolos especiais",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Numeric": {
|
||||
"message": "Numérico",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Uppercase": {
|
||||
"message": "Maiúsculas",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Lowercase": {
|
||||
"message": "Minúsculas",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Exclude": {
|
||||
"message": "Excluir",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Similar": {
|
||||
"message": "Semelhante",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Ambiguous": {
|
||||
"message": "Ambíguo",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Repeating": {
|
||||
"message": "Repetido",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Add_shortcut_to_context_menu": {
|
||||
"message": "Adicionar atalho ao menu de contexto",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Right_click_password_field_to_quickly_generate_password": {
|
||||
"message": "Clique com o botão direito do mouse no campo de senha para gerar a senha rapidamente",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Automatically_copy_to_clipboard": {
|
||||
"message": "Copiar automaticamente para a área de transferência",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"About": {
|
||||
"message": "Sobre",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Developed_by_Eugene_Fox": {
|
||||
"message": "Desenvolvido por Eugene Fox",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Licensed_under": {
|
||||
"message": "Licenciado sob",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"MIT_license": {
|
||||
"message": "Licença MIT",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Want_to_contribute_translation_for_your_language_": {
|
||||
"message": "Quer contribuir com a tradução para o seu idioma?",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Read_this_to_get_started": {
|
||||
"message": "Leia isto para começar",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"My_website": {
|
||||
"message": "Meu website",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Source_code": {
|
||||
"message": "Código fonte",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Changelog": {
|
||||
"message": "Registro de alterações",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Leave_feedback": {
|
||||
"message": "Deixar feedback",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Buy_me_a_coffee": {
|
||||
"message": "Compre-me um café",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Set_name": {
|
||||
"message": "Nome",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Characters": {
|
||||
"message": "Caracteres",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"__etc_": {
|
||||
"message": ", etc.",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"OK": {
|
||||
"message": "OK",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included": {
|
||||
"message": "Caracteres minúsculos ou maiúsculos devem ser incluídos",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters": {
|
||||
"message": "O comprimento selecionado é muito longo para excluir caracteres repetidos",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Quick_generator_is_only_available_on_password_fields": {
|
||||
"message": "O gerador rápido está disponível apenas em campos de senha",
|
||||
"description": "ContentService.tsx"
|
||||
},
|
||||
"Quick_generate_password": {
|
||||
"message": "Gerar senha rápida",
|
||||
"description": "BackgroundService.tsx"
|
||||
}
|
||||
}
|
||||
@@ -1,216 +1,173 @@
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"name": {
|
||||
"message": "Генератор паролей",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"description":
|
||||
{
|
||||
"description": {
|
||||
"message": "Расширение, позволяющее легко генерировать сложные и надежные пароли в один клик",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"author":
|
||||
{
|
||||
"author": {
|
||||
"message": "Евгений Лис",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"Password_generator":
|
||||
{
|
||||
"Password_generator": {
|
||||
"message": "Генератор паролей",
|
||||
"description": "App.tsx"
|
||||
},
|
||||
"Copy":
|
||||
{
|
||||
"Copy": {
|
||||
"message": "Копировать",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Generate_new":
|
||||
{
|
||||
"Generate_new": {
|
||||
"message": "Создать новый",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Exclude_special_symbols_one_time":
|
||||
{
|
||||
"Exclude_special_symbols_one_time": {
|
||||
"message": "Сгенерировать пароль без спецсимволов",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Include_special_symbols_one_time":
|
||||
{
|
||||
"Include_special_symbols_one_time": {
|
||||
"message": "Сгенерировать пароль со спецсимволами",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Settings":
|
||||
{
|
||||
"Settings": {
|
||||
"message": "Настройки",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Password_length":
|
||||
{
|
||||
"Password_length": {
|
||||
"message": "Длина пароля",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Recommended_password_length":
|
||||
{
|
||||
"Recommended_password_length": {
|
||||
"message": "Рекомендуемая длина пароля",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Character_options":
|
||||
{
|
||||
"Character_options": {
|
||||
"message": "Настройки символов",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Include":
|
||||
{
|
||||
"Include": {
|
||||
"message": "Включить",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Special_symbols":
|
||||
{
|
||||
"Special_symbols": {
|
||||
"message": "Специальные символы",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Numeric":
|
||||
{
|
||||
"Numeric": {
|
||||
"message": "Цифры",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Uppercase":
|
||||
{
|
||||
"Uppercase": {
|
||||
"message": "Прописные буквы",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Lowercase":
|
||||
{
|
||||
"Lowercase": {
|
||||
"message": "Строчные буквы",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Exclude":
|
||||
{
|
||||
"Exclude": {
|
||||
"message": "Исключить",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Similar":
|
||||
{
|
||||
"Similar": {
|
||||
"message": "Похожие",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Ambiguous":
|
||||
{
|
||||
"Ambiguous": {
|
||||
"message": "Особые",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Repeating":
|
||||
{
|
||||
"Repeating": {
|
||||
"message": "Повторяющиеся",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Add_shortcut_to_context_menu":
|
||||
{
|
||||
"Add_shortcut_to_context_menu": {
|
||||
"message": "Добавить расширение в контекстное меню",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Right_click_password_field_to_quickly_generate_password":
|
||||
{
|
||||
"Right_click_password_field_to_quickly_generate_password": {
|
||||
"message": "Щелкните правой кнопкой мыши по полю ввода пароля, чтобы быстро сгенерировать пароль",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Automatically_copy_to_clipboard":
|
||||
{
|
||||
"Automatically_copy_to_clipboard": {
|
||||
"message": "Автоматически копировать в буфер обмена",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"About":
|
||||
{
|
||||
"About": {
|
||||
"message": "О расширении",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Developed_by_Eugene_Fox":
|
||||
{
|
||||
"Developed_by_Eugene_Fox": {
|
||||
"message": "Разработчик Евгений Лис",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Licensed_under":
|
||||
{
|
||||
"Licensed_under": {
|
||||
"message": "Лицензия",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"MIT_license":
|
||||
{
|
||||
"MIT_license": {
|
||||
"message": "MIT",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Want_to_contribute_translation_for_your_language_":
|
||||
{
|
||||
"Want_to_contribute_translation_for_your_language_": {
|
||||
"message": "Хотите помочь с переводом на свой язык?",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Read_this_to_get_started":
|
||||
{
|
||||
"Read_this_to_get_started": {
|
||||
"message": "Прочтите эту статью",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"My_website":
|
||||
{
|
||||
"My_website": {
|
||||
"message": "Мой сайт",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Source_code":
|
||||
{
|
||||
"Source_code": {
|
||||
"message": "Исходный код",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Changelog":
|
||||
{
|
||||
"Changelog": {
|
||||
"message": "Список изменений",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Leave_feedback":
|
||||
{
|
||||
"Leave_feedback": {
|
||||
"message": "Оставить отзыв",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Buy_me_a_coffee":
|
||||
{
|
||||
"Buy_me_a_coffee": {
|
||||
"message": "Спонсировать",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Set_name":
|
||||
{
|
||||
"Set_name": {
|
||||
"message": "Название",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Characters":
|
||||
{
|
||||
"Characters": {
|
||||
"message": "Символы",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"__etc_":
|
||||
{
|
||||
"__etc_": {
|
||||
"message": " и т.д.",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"OK":
|
||||
{
|
||||
"OK": {
|
||||
"message": "ОК",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included":
|
||||
{
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included": {
|
||||
"message": "Должны быть включены строчные или прописные буквы",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters":
|
||||
{
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters": {
|
||||
"message": "Выбранная длина слишком велика для исключения повторяющихся символов",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Quick_generator_is_only_available_on_password_fields":
|
||||
{
|
||||
"Quick_generator_is_only_available_on_password_fields": {
|
||||
"message": "Быстрый генератор доступен только для полей ввода пароля",
|
||||
"description": "ContentService.tsx"
|
||||
},
|
||||
"Quick_generate_password":
|
||||
{
|
||||
"Quick_generate_password": {
|
||||
"message": "Сгенерировать пароль",
|
||||
"description": "BackgroundService.tsx"
|
||||
}
|
||||
|
||||
@@ -1,216 +1,173 @@
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"name": {
|
||||
"message": "Генератор паролів",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"description":
|
||||
{
|
||||
"description": {
|
||||
"message": "Розширення, яке дозволяє легко генерувати складні та надійні паролі в один клік",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"author":
|
||||
{
|
||||
"author": {
|
||||
"message": "Євген Лис",
|
||||
"description": "manifest.json"
|
||||
},
|
||||
"Password_generator":
|
||||
{
|
||||
"Password_generator": {
|
||||
"message": "Генератор паролів",
|
||||
"description": "App.tsx"
|
||||
},
|
||||
"Copy":
|
||||
{
|
||||
"Copy": {
|
||||
"message": "Копіювати",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Generate_new":
|
||||
{
|
||||
"Generate_new": {
|
||||
"message": "Генерувати новий",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Exclude_special_symbols_one_time":
|
||||
{
|
||||
"Exclude_special_symbols_one_time": {
|
||||
"message": "Генерувати пароль без спеціальних символів",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Include_special_symbols_one_time":
|
||||
{
|
||||
"Include_special_symbols_one_time": {
|
||||
"message": "Генерувати пароль з спеціальними символами",
|
||||
"description": "PasswordView.tsx"
|
||||
},
|
||||
"Settings":
|
||||
{
|
||||
"Settings": {
|
||||
"message": "Налаштування",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Password_length":
|
||||
{
|
||||
"Password_length": {
|
||||
"message": "Довжина паролю",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Recommended_password_length":
|
||||
{
|
||||
"Recommended_password_length": {
|
||||
"message": "Рекомендована довжина паролю",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Character_options":
|
||||
{
|
||||
"Character_options": {
|
||||
"message": "Параметри символів",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Include":
|
||||
{
|
||||
"Include": {
|
||||
"message": "Включити",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Special_symbols":
|
||||
{
|
||||
"Special_symbols": {
|
||||
"message": "Спеціальні символи",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Numeric":
|
||||
{
|
||||
"Numeric": {
|
||||
"message": "Цифри",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Uppercase":
|
||||
{
|
||||
"Uppercase": {
|
||||
"message": "Великі літери",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Lowercase":
|
||||
{
|
||||
"Lowercase": {
|
||||
"message": "Малі літери",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Exclude":
|
||||
{
|
||||
"Exclude": {
|
||||
"message": "Виключити",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Similar":
|
||||
{
|
||||
"Similar": {
|
||||
"message": "Схожі",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Ambiguous":
|
||||
{
|
||||
"Ambiguous": {
|
||||
"message": "Особливі",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Repeating":
|
||||
{
|
||||
"Repeating": {
|
||||
"message": "Повторювані",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Add_shortcut_to_context_menu":
|
||||
{
|
||||
"Add_shortcut_to_context_menu": {
|
||||
"message": "Додати розширення до контекстного меню",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Right_click_password_field_to_quickly_generate_password":
|
||||
{
|
||||
"Right_click_password_field_to_quickly_generate_password": {
|
||||
"message": "Правий клік на поле вводу паролю для швидкого генерування паролю",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"Automatically_copy_to_clipboard":
|
||||
{
|
||||
"Automatically_copy_to_clipboard": {
|
||||
"message": "Автоматично копіювати в буфер обміну",
|
||||
"description": "SettingsSection.tsx"
|
||||
},
|
||||
"About":
|
||||
{
|
||||
"About": {
|
||||
"message": "Про розширення",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Developed_by_Eugene_Fox":
|
||||
{
|
||||
"Developed_by_Eugene_Fox": {
|
||||
"message": "Розроблено Євгеном Лисом",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Licensed_under":
|
||||
{
|
||||
"Licensed_under": {
|
||||
"message": "Ліцензовано під",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"MIT_license":
|
||||
{
|
||||
"MIT_license": {
|
||||
"message": "MIT",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Want_to_contribute_translation_for_your_language_":
|
||||
{
|
||||
"Want_to_contribute_translation_for_your_language_": {
|
||||
"message": "Хочете допомогти перекласти розширення на свою мову?",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Read_this_to_get_started":
|
||||
{
|
||||
"Read_this_to_get_started": {
|
||||
"message": "Прочитайте цю статтю",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"My_website":
|
||||
{
|
||||
"My_website": {
|
||||
"message": "Моя веб-сторінка",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Source_code":
|
||||
{
|
||||
"Source_code": {
|
||||
"message": "Вихідний код",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Changelog":
|
||||
{
|
||||
"Changelog": {
|
||||
"message": "Список змін",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Leave_feedback":
|
||||
{
|
||||
"Leave_feedback": {
|
||||
"message": "Залишити відгук",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Buy_me_a_coffee":
|
||||
{
|
||||
"Buy_me_a_coffee": {
|
||||
"message": "Підтримати",
|
||||
"description": "AboutSection.tsx"
|
||||
},
|
||||
"Set_name":
|
||||
{
|
||||
"Set_name": {
|
||||
"message": "Назва",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Characters":
|
||||
{
|
||||
"Characters": {
|
||||
"message": "Символи",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"__etc_":
|
||||
{
|
||||
"__etc_": {
|
||||
"message": " і т.д.",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"OK":
|
||||
{
|
||||
"OK": {
|
||||
"message": "OK",
|
||||
"description": "CharacterHelpDialog.tsx"
|
||||
},
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included":
|
||||
{
|
||||
"Either_lowercase_or_uppercase_characters_must_be_included": {
|
||||
"message": "Повинні бути включені малі або великі літери",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters":
|
||||
{
|
||||
"Selected_length_is_too_long_to_exclude_repeating_characters": {
|
||||
"message": "Вибрана довжина занадто велика для виключення повторюваних символів",
|
||||
"description": "Generator.tsx"
|
||||
},
|
||||
"Quick_generator_is_only_available_on_password_fields":
|
||||
{
|
||||
"Quick_generator_is_only_available_on_password_fields": {
|
||||
"message": "Швидкий генератор доступний тільки для полів вводу паролів",
|
||||
"description": "ContentService.tsx"
|
||||
},
|
||||
"Quick_generate_password":
|
||||
{
|
||||
"Quick_generate_password": {
|
||||
"message": "Згенерувати пароль",
|
||||
"description": "BackgroundService.tsx"
|
||||
}
|
||||
|
||||
+5
-2
@@ -2,9 +2,12 @@
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Password Generator</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charset="utf-8" />
|
||||
<title>Password Generator</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
+11
-28
@@ -1,56 +1,39 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/chrome-manifest.json",
|
||||
"manifest_version": 3,
|
||||
|
||||
"name": "__MSG_name__",
|
||||
"description": "__MSG_description__",
|
||||
"author": "__MSG_author__",
|
||||
|
||||
"version": "2.0.0",
|
||||
"default_locale": "en",
|
||||
|
||||
"permissions":
|
||||
[
|
||||
"permissions": [
|
||||
"storage",
|
||||
"contextMenus",
|
||||
"clipboardWrite"
|
||||
],
|
||||
|
||||
"background":
|
||||
{
|
||||
"background": {
|
||||
"service_worker": "./static/js/background.js",
|
||||
"type": "module"
|
||||
},
|
||||
"content_scripts":
|
||||
[
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [ "<all_urls>" ],
|
||||
"js": [ "./static/js/contentScript.js" ],
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"js": [
|
||||
"./static/js/contentScript.js"
|
||||
],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
|
||||
"action":
|
||||
{
|
||||
"action": {
|
||||
"default_popup": "index.html",
|
||||
"default_title": "__MSG_name__"
|
||||
},
|
||||
|
||||
"icons":
|
||||
{
|
||||
"icons": {
|
||||
"128": "icons/icon-128.png",
|
||||
"48": "icons/icon-48.png",
|
||||
"32": "icons/icon-32.png",
|
||||
"16": "icons/icon-16.png"
|
||||
},
|
||||
|
||||
"browser_specific_settings":
|
||||
{
|
||||
"gecko":
|
||||
{
|
||||
"id": "passwordgenerator@xfox111.net",
|
||||
"strict_min_version": "58.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,45 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/chrome-manifest.json",
|
||||
"manifest_version": 2,
|
||||
|
||||
"name": "__MSG_name__",
|
||||
"description": "__MSG_description__",
|
||||
"author": "__MSG_author__",
|
||||
|
||||
"version": "2.0.0",
|
||||
"default_locale": "en",
|
||||
|
||||
"permissions":
|
||||
[
|
||||
"permissions": [
|
||||
"storage",
|
||||
"contextMenus",
|
||||
"clipboardWrite"
|
||||
],
|
||||
|
||||
"background":
|
||||
{
|
||||
"scripts": [ "./static/js/background.js" ],
|
||||
"background": {
|
||||
"scripts": [
|
||||
"./static/js/background.js"
|
||||
],
|
||||
"persistent": true
|
||||
},
|
||||
"content_scripts":
|
||||
[
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [ "<all_urls>" ],
|
||||
"js": [ "./static/js/contentScript.js" ],
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"js": [
|
||||
"./static/js/contentScript.js"
|
||||
],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
|
||||
"browser_action":
|
||||
{
|
||||
"browser_action": {
|
||||
"default_popup": "index.html",
|
||||
"default_title": "__MSG_name__"
|
||||
},
|
||||
|
||||
"icons":
|
||||
{
|
||||
"icons": {
|
||||
"128": "icons/icon-128.png",
|
||||
"48": "icons/icon-48.png",
|
||||
"32": "icons/icon-32.png",
|
||||
"16": "icons/icon-16.png"
|
||||
},
|
||||
|
||||
"browser_specific_settings":
|
||||
{
|
||||
"gecko":
|
||||
{
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "passwordgenerator@xfox111.net",
|
||||
"strict_min_version": "58.0"
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
body
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main
|
||||
{
|
||||
width: 400px;
|
||||
padding: 8px;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p
|
||||
{
|
||||
@@ -43,12 +51,19 @@ main
|
||||
}
|
||||
}
|
||||
|
||||
button.fui-Link
|
||||
{
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.scaleUpIn
|
||||
{
|
||||
animation-name: scaleUpInAnim;
|
||||
animation-timing-function: var(--curveEasyEaseMax);
|
||||
animation-duration: .5s;
|
||||
}
|
||||
|
||||
@keyframes scaleUpInAnim
|
||||
{
|
||||
from
|
||||
@@ -56,6 +71,7 @@ main
|
||||
transform: scale(.5);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to
|
||||
{
|
||||
transform: scale(1);
|
||||
@@ -69,12 +85,14 @@ main
|
||||
animation-timing-function: var(--curveEasyEaseMax);
|
||||
animation-duration: .5s;
|
||||
}
|
||||
|
||||
@keyframes spinAnim
|
||||
{
|
||||
from
|
||||
{
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to
|
||||
{
|
||||
transform: rotate(360deg);
|
||||
@@ -87,12 +105,14 @@ main
|
||||
animation-timing-function: var(--curveDecelerateMin);
|
||||
animation-duration: .5s;
|
||||
}
|
||||
|
||||
@keyframes fadeInAnim
|
||||
{
|
||||
from
|
||||
{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to
|
||||
{
|
||||
opacity: 1;
|
||||
|
||||
@@ -8,6 +8,7 @@ import PasswordView from "./Components/PasswordView";
|
||||
import Settings from "./Utils/Settings";
|
||||
import GeneratorOptions from "./Utils/GeneratorOptions";
|
||||
import { loc } from "./Utils/Localization";
|
||||
import Snow from "./Holidays/Snow";
|
||||
|
||||
interface IStates
|
||||
{
|
||||
@@ -63,6 +64,8 @@ export default class App extends React.Component<IProps, IStates>
|
||||
return (
|
||||
<FluentProvider theme={ this.state.theme }>
|
||||
<main className="stack gap">
|
||||
<Snow />
|
||||
|
||||
<header className="stack horizontal gap">
|
||||
<Title2 as="h1">{ loc("Password generator") }</Title2>
|
||||
<Text as="span">v{ Package.version }</Text>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat-20110816.dtd">
|
||||
<svg id="BuyMeACoffee" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 884 1279" width="16" height="16">
|
||||
<defs>
|
||||
<style type="text/css">
|
||||
|
||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.0 KiB |
@@ -3,6 +3,7 @@ import { InfoRegular, PersonFeedbackRegular } from "@fluentui/react-icons";
|
||||
import { ReactComponent as BuyMeACoffee } from "../Assets/BuyMeACoffee.svg";
|
||||
import React from "react";
|
||||
import { loc } from "../Utils/Localization";
|
||||
import * as Platform from "react-device-detect";
|
||||
|
||||
export default class AboutSection extends React.Component
|
||||
{
|
||||
@@ -32,7 +33,7 @@ export default class AboutSection extends React.Component
|
||||
<div className="stack horizontal gap">
|
||||
<Button
|
||||
as="a" target="_blank"
|
||||
href="mailto:feedback@xfox111.net"
|
||||
href={ this.GetFeedbackLink() }
|
||||
appearance="primary" icon={ <PersonFeedbackRegular /> }>
|
||||
|
||||
{ loc("Leave feedback") }
|
||||
@@ -51,4 +52,16 @@ export default class AboutSection extends React.Component
|
||||
</AccordionItem>
|
||||
);
|
||||
}
|
||||
|
||||
private GetFeedbackLink(): string
|
||||
{
|
||||
if (Platform.isEdgeChromium)
|
||||
return "https://microsoftedge.microsoft.com/addons/detail/password-generator/manimdhobjbkfpeeehlhhneookiokpbj";
|
||||
else if (Platform.isChrome)
|
||||
return "https://chrome.google.com/webstore/detail/password-generator/jnjobgjobffgmgfnkpkjfjkkfhfikmfl";
|
||||
else if (Platform.isFirefox)
|
||||
return "https://addons.mozilla.org/en-US/firefox/addon/easy-password-generator";
|
||||
else
|
||||
return "mailto:feedback@xfox111.net";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Button, Text } from "@fluentui/react-components";
|
||||
import { Dialog, DialogTrigger, DialogSurface, DialogTitle, DialogBody, Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell, DialogActions } from "@fluentui/react-components/unstable";
|
||||
import { Button, Text, Dialog, DialogTrigger, DialogSurface, DialogTitle, DialogBody, DialogActions, DialogContent, Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell } from "@fluentui/react-components";
|
||||
import { QuestionCircleRegular } from "@fluentui/react-icons";
|
||||
import React from "react";
|
||||
import Generator from "../Utils/Generator";
|
||||
@@ -15,60 +14,62 @@ export default class CharacterHelpDialog extends React.Component
|
||||
<Button appearance="subtle" style={ { marginLeft: 5 } } icon={ <QuestionCircleRegular /> } />
|
||||
</DialogTrigger>
|
||||
<DialogSurface aria-label="label">
|
||||
<DialogTitle>{ loc("Character options") }</DialogTitle>
|
||||
<DialogBody>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>{ loc("Set_name") }</TableHeaderCell>
|
||||
<TableHeaderCell>{ loc("Characters") }</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Lowercase") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Lowercase.substring(0, 10) }{ loc(", etc.") }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Uppercase") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Uppercase.substring(0, 10) }{ loc(", etc.") }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Numeric") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Numeric }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Special symbols") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.SpecialCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Ambiguous") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.AmbiguousCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Similar") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.SimilarCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DialogTitle>{ loc("Character options") }</DialogTitle>
|
||||
<DialogContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>{ loc("Set_name") }</TableHeaderCell>
|
||||
<TableHeaderCell>{ loc("Characters") }</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Lowercase") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Lowercase.substring(0, 10) }{ loc(", etc.") }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Uppercase") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Uppercase.substring(0, 10) }{ loc(", etc.") }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Numeric") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.Numeric }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Special symbols") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.SpecialCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Ambiguous") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.AmbiguousCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>{ loc("Similar") }</TableCell>
|
||||
<TableCell>
|
||||
<Text font="monospace">{ Generator.SimilarCharacters }</Text>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<DialogTrigger>
|
||||
<Button appearance="secondary">{ loc("OK") }</Button>
|
||||
</DialogTrigger>
|
||||
</DialogActions>
|
||||
</DialogBody>
|
||||
<DialogActions>
|
||||
<DialogTrigger>
|
||||
<Button appearance="secondary">{ loc("OK") }</Button>
|
||||
</DialogTrigger>
|
||||
</DialogActions>
|
||||
</DialogSurface>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class PasswordView extends React.Component<IProps, IStates>
|
||||
};
|
||||
}
|
||||
|
||||
private OnCopyPassword(password : string): void
|
||||
private OnCopyPassword(password: string): void
|
||||
{
|
||||
console.log("PasswordView.OnCopyPassword");
|
||||
|
||||
@@ -50,7 +50,7 @@ export default class PasswordView extends React.Component<IProps, IStates>
|
||||
{
|
||||
console.log("PasswordView.OnRefreshPassword");
|
||||
|
||||
let password : string = Generator.GeneratePassword(this.props.generatorOptions);
|
||||
let password: string = Generator.GeneratePassword(this.props.generatorOptions);
|
||||
|
||||
this.setState({ password });
|
||||
|
||||
@@ -69,7 +69,7 @@ export default class PasswordView extends React.Component<IProps, IStates>
|
||||
if (JSON.stringify(prevProps.generatorOptions) === JSON.stringify(this.props.generatorOptions))
|
||||
return;
|
||||
|
||||
let error : string = Generator.ValidateProps(this.props.generatorOptions);
|
||||
let error: string = Generator.ValidateProps(this.props.generatorOptions);
|
||||
let password = Generator.GeneratePassword(this.props.generatorOptions);
|
||||
|
||||
this.setState({ password, error });
|
||||
@@ -78,14 +78,14 @@ export default class PasswordView extends React.Component<IProps, IStates>
|
||||
this.OnCopyPassword(password);
|
||||
}
|
||||
|
||||
private AlterSpecialsOnce(useSpecials : boolean) : void
|
||||
private AlterSpecialsOnce(useSpecials: boolean): void
|
||||
{
|
||||
console.log("PasswordView.AlterSpecialsOnce", `useSpecials: ${useSpecials}`);
|
||||
|
||||
let options : GeneratorOptions = { ...this.props.generatorOptions, Special: useSpecials, ExcludeAmbiguous: true };
|
||||
let options: GeneratorOptions = { ...this.props.generatorOptions, Special: useSpecials, ExcludeAmbiguous: true };
|
||||
|
||||
let error : string = Generator.ValidateProps(options);
|
||||
let password : string = Generator.GeneratePassword(options);
|
||||
let error: string = Generator.ValidateProps(options);
|
||||
let password: string = Generator.GeneratePassword(options);
|
||||
|
||||
this.setState({ password, error });
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ export default class SettingsSection extends React.Component<IProps>
|
||||
{
|
||||
public render(): JSX.Element
|
||||
{
|
||||
let options : GeneratorOptions = this.props.generatorOptions;
|
||||
let settings : Settings = this.props.settings;
|
||||
let options: GeneratorOptions = this.props.generatorOptions;
|
||||
let settings: Settings = this.props.settings;
|
||||
|
||||
return (
|
||||
<AccordionItem value="settings">
|
||||
@@ -28,9 +28,9 @@ export default class SettingsSection extends React.Component<IProps>
|
||||
<div className="stack">
|
||||
<Input
|
||||
id="pwd-length"
|
||||
value={ options.Length.toString() }
|
||||
value={ options.Length?.toString() }
|
||||
onChange={ (_, e) => GeneratorOptions.Update({ Length: parseInt(e.value) }) }
|
||||
type="number" min={ 4 } />
|
||||
type="number" min={ 4 } minLength={ 1 } />
|
||||
<Text size={ 200 }>{ loc("Recommended password length") } <b>16-32</b></Text>
|
||||
</div>
|
||||
<Divider />
|
||||
@@ -64,12 +64,14 @@ export default class SettingsSection extends React.Component<IProps>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="stack">
|
||||
<div>
|
||||
<Tooltip content={ loc("Right-click password field to quickly generate password") } relationship="description">
|
||||
<Checkbox label={ <Text>{loc("Add shortcut to context menu")} <QuestionCircleRegular /></Text> }
|
||||
checked={ settings.AddContext } onChange={ (_, e) => Settings.Update({ AddContext: e.checked as boolean }) } />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Checkbox
|
||||
checked={ settings.AddContext }
|
||||
onChange={ (_, e) => Settings.Update({ AddContext: e.checked as boolean }) }
|
||||
label={
|
||||
<Tooltip content={ loc("Right-click password field to quickly generate password") } relationship="description">
|
||||
<Text>{ loc("Add shortcut to context menu") } <QuestionCircleRegular /></Text>
|
||||
</Tooltip>
|
||||
} />
|
||||
<Checkbox label={ loc("Automatically copy to clipboard") }
|
||||
checked={ settings.Autocopy } onChange={ (_, e) => Settings.Update({ Autocopy: e.checked as boolean }) } />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
.snowflakeContainer
|
||||
{
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.snowflake
|
||||
{
|
||||
--size: 1px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
|
||||
@media (prefers-color-scheme: light)
|
||||
{
|
||||
background: var(--colorPalettePlatinumBorderActive);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes snowfall
|
||||
{
|
||||
0%
|
||||
{
|
||||
transform: translate3d(var(--left-ini), 0, 0);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
100%
|
||||
{
|
||||
transform: translate3d(var(--left-end), 610px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 50
|
||||
{
|
||||
.snowflake:nth-child(#{$i})
|
||||
{
|
||||
--size: #{random(5)}px;
|
||||
--left-ini: #{random(20) - 10}vw;
|
||||
--left-end: #{random(20) - 10}vw;
|
||||
left: #{random(100)}vw;
|
||||
animation: snowfall #{5 + random(10)}s linear infinite;
|
||||
animation-delay: -#{random(10)}s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
import "./Snow.scss";
|
||||
|
||||
export default class Snow extends React.Component
|
||||
{
|
||||
public render(): JSX.Element
|
||||
{
|
||||
// Show snowflakes only from 15th of December till 10th of January
|
||||
let now = new Date();
|
||||
|
||||
if (
|
||||
(now.getMonth() !== 11 || now.getDate() < 15) &&
|
||||
(now.getMonth() !== 0 || now.getDate() > 10)
|
||||
)
|
||||
return <></>;
|
||||
|
||||
return (
|
||||
<div className="snowflakeContainer">
|
||||
{ [...Array(50)].map((_, i) => <div key={i} className="snowflake" />) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,55 @@
|
||||
// BackgroundService.ts
|
||||
// Background script that handles the context menu visibility
|
||||
|
||||
import { Tabs, Menus } from "webextension-polyfill";
|
||||
import browser from "../Utils/Browser";
|
||||
import { loc } from "../Utils/Localization";
|
||||
|
||||
function UpdateContextMenu(isEnabled: boolean) : void
|
||||
function UpdateContextMenu(isEnabled: boolean): void
|
||||
{
|
||||
console.log("BackgroundService.UpdateContextMenu", isEnabled);
|
||||
chrome.contextMenus.update("generatePassword", { visible: isEnabled });
|
||||
browser.contextMenus.update("generatePassword", { visible: isEnabled });
|
||||
}
|
||||
|
||||
async function OnContextClick(info : chrome.contextMenus.OnClickData) : Promise<void>
|
||||
async function OnContextClick(info: Menus.OnClickData): Promise<void>
|
||||
{
|
||||
console.log("BackgroundService.OnContextClick", info);
|
||||
|
||||
let tabInfo : chrome.tabs.Tab[] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
|
||||
let tabInfo: Tabs.Tab[] = await browser.tabs.query({ active: true, currentWindow: true });
|
||||
console.log("BackgroundService.OnContextClick", tabInfo);
|
||||
|
||||
chrome.tabs.sendMessage<string>(tabInfo[0].id, info.menuItemId as string);
|
||||
browser.tabs.sendMessage(tabInfo[0].id, info.menuItemId as string);
|
||||
}
|
||||
|
||||
if (!chrome.runtime.onInstalled.hasListeners())
|
||||
chrome.runtime.onInstalled.addListener(async () =>
|
||||
{
|
||||
console.log("[BackgroundService] chrome.runtime.onInstalled");
|
||||
chrome.contextMenus.removeAll();
|
||||
async function OnInstalled(): Promise<void>
|
||||
{
|
||||
console.log("[BackgroundService] browser.runtime.onInstalled");
|
||||
browser.contextMenus.removeAll();
|
||||
|
||||
chrome.contextMenus.create(
|
||||
{
|
||||
title: loc("Quick generate password"),
|
||||
contexts: [ "editable" ],
|
||||
id: "generatePassword"
|
||||
}
|
||||
);
|
||||
|
||||
let settings : { [key : string]: any } = await chrome.storage.sync.get({ AddContext: true });
|
||||
|
||||
UpdateContextMenu(settings.AddContext);
|
||||
});
|
||||
|
||||
if (!chrome.contextMenus.onClicked.hasListeners())
|
||||
chrome.contextMenus.onClicked.addListener(OnContextClick);
|
||||
|
||||
if (!chrome.storage.sync.onChanged.hasListeners())
|
||||
chrome.storage.sync.onChanged.addListener(changes =>
|
||||
browser.contextMenus.create(
|
||||
{
|
||||
console.log("[BackgroundService] chrome.storage.sync.onChanged", changes);
|
||||
if (changes.AddContext?.newValue !== undefined)
|
||||
UpdateContextMenu(changes.AddContext.newValue);
|
||||
});
|
||||
title: loc("Quick generate password"),
|
||||
contexts: ["editable"],
|
||||
id: "generatePassword"
|
||||
}
|
||||
);
|
||||
|
||||
let settings: { [key: string]: any; } = await browser.storage.sync.get({ AddContext: true });
|
||||
|
||||
UpdateContextMenu(settings.AddContext);
|
||||
}
|
||||
|
||||
async function OnStorageChanged(changes: any): Promise<void>
|
||||
{
|
||||
console.log("[BackgroundService] browser.storage.sync.onChanged", changes);
|
||||
if (changes.AddContext?.newValue !== undefined)
|
||||
UpdateContextMenu(changes.AddContext.newValue);
|
||||
}
|
||||
|
||||
if (!browser.runtime.onInstalled.hasListener(OnInstalled))
|
||||
browser.runtime.onInstalled.addListener(OnInstalled);
|
||||
|
||||
if (!browser.contextMenus.onClicked.hasListener(OnContextClick))
|
||||
browser.contextMenus.onClicked.addListener(OnContextClick);
|
||||
|
||||
if (!browser.storage.sync.onChanged.hasListener(OnStorageChanged))
|
||||
browser.storage.sync.onChanged.addListener(OnStorageChanged);
|
||||
|
||||
@@ -1,37 +1,40 @@
|
||||
// ContentService.ts
|
||||
// Content script that handles quick password generation through context menu
|
||||
|
||||
import browser from "../Utils/Browser";
|
||||
import Generator from "../Utils/Generator";
|
||||
import GeneratorOptions from "../Utils/GeneratorOptions";
|
||||
import { loc } from "../Utils/Localization";
|
||||
|
||||
if (!chrome.runtime.onMessage.hasListeners())
|
||||
chrome.runtime.onMessage.addListener(async message =>
|
||||
async function OnMessage(message: any): Promise<void>
|
||||
{
|
||||
console.log("[ContentService] browser.runtime.onMessage", message);
|
||||
|
||||
if (message === "generatePassword")
|
||||
{
|
||||
console.log("[ContentService] chrome.runtime.onMessage", message);
|
||||
let generatorOptions: GeneratorOptions = await GeneratorOptions.Init();
|
||||
let password: string = Generator.GeneratePassword(generatorOptions);
|
||||
|
||||
if (message === "generatePassword")
|
||||
let input: HTMLInputElement = document.activeElement as HTMLInputElement;
|
||||
|
||||
if (!["INPUT", "TEXTAREA"].includes(input.tagName))
|
||||
return;
|
||||
|
||||
console.log("[ContentService] browser.runtime.onMessage", input);
|
||||
|
||||
if (input.tagName !== "INPUT" || input.readOnly || !["text", "password"].includes(input.type))
|
||||
{
|
||||
let generatorOptions : GeneratorOptions = await GeneratorOptions.Init();
|
||||
let password : string = Generator.GeneratePassword(generatorOptions);
|
||||
|
||||
let input : HTMLInputElement = document.activeElement as HTMLInputElement;
|
||||
|
||||
if (![ "INPUT", "TEXTAREA" ].includes(input.tagName))
|
||||
return;
|
||||
|
||||
console.log("[ContentService] chrome.runtime.onMessage", input);
|
||||
|
||||
if (input.tagName !== "INPUT" || input.readOnly || ![ "text", "password" ].includes(input.type))
|
||||
{
|
||||
window.alert(loc("Quick generator is only available on password fields"));
|
||||
return;
|
||||
}
|
||||
|
||||
input.focus();
|
||||
input.value = password;
|
||||
window.navigator.clipboard.writeText(password);
|
||||
window.alert(loc("Quick generator is only available on password fields"));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
input.focus();
|
||||
input.value = password;
|
||||
window.navigator.clipboard.writeText(password);
|
||||
}
|
||||
}
|
||||
|
||||
if (!browser.runtime.onMessage.hasListener(OnMessage))
|
||||
browser.runtime.onMessage.addListener(OnMessage);
|
||||
|
||||
console.log("[ContentService] Loaded");
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import Browser from "webextension-polyfill";
|
||||
|
||||
const browser: typeof Browser = (process.env.NODE_ENV !== "development") ? require("webextension-polyfill") : null;
|
||||
export default browser;
|
||||
+22
-14
@@ -10,21 +10,24 @@ export default class Generator
|
||||
public static AmbiguousCharacters = "{}[]()/\\'\"`~,;:.<>";
|
||||
public static SimilarCharacters = "il1Lo0O";
|
||||
|
||||
public static GeneratePassword(props : GeneratorOptions) : string
|
||||
public static GeneratePassword(props: GeneratorOptions): string
|
||||
{
|
||||
if (!props.Length || isNaN(props.Length) || props.Length < 4)
|
||||
props.Length = 4;
|
||||
|
||||
// Validating parameters
|
||||
if (this.ValidateProps(props))
|
||||
return "";
|
||||
|
||||
// Generating password
|
||||
let availableCharacters : string = this.GetAvailableCharacters(props);
|
||||
let requiredCharacters : string = this.GetRequiredCharacters(props);
|
||||
let availableCharacters: string = this.GetAvailableCharacters(props);
|
||||
let requiredCharacters: string = this.GetRequiredCharacters(props);
|
||||
|
||||
let password : string = "";
|
||||
let password: string = "";
|
||||
|
||||
for (let i = 0; i < props.Length; i++)
|
||||
{
|
||||
let char : string = this.PickRandomFromArray(availableCharacters);
|
||||
let char: string = this.PickRandomFromArray(availableCharacters);
|
||||
|
||||
if (props.ExcludeRepeating && password.includes(char))
|
||||
i--;
|
||||
@@ -43,12 +46,15 @@ export default class Generator
|
||||
return password;
|
||||
}
|
||||
|
||||
public static ValidateProps(props : GeneratorOptions): string
|
||||
public static ValidateProps(props: GeneratorOptions): string
|
||||
{
|
||||
if (!props.Length || isNaN(props.Length) || props.Length < 4)
|
||||
props.Length = 4;
|
||||
|
||||
if (!props.Lowercase && !props.Uppercase)
|
||||
return loc("Either lowercase or uppercase characters must be included");
|
||||
|
||||
let availableCharacters : string = this.GetAvailableCharacters(props);
|
||||
let availableCharacters: string = this.GetAvailableCharacters(props);
|
||||
|
||||
if (props.ExcludeRepeating && availableCharacters.length < props.Length)
|
||||
return loc("Selected length is too long to exclude repeating characters");
|
||||
@@ -56,9 +62,9 @@ export default class Generator
|
||||
return "";
|
||||
}
|
||||
|
||||
private static GetAvailableCharacters(props : GeneratorOptions) : string
|
||||
private static GetAvailableCharacters(props: GeneratorOptions): string
|
||||
{
|
||||
let availableCharacters : string = "";
|
||||
let availableCharacters: string = "";
|
||||
|
||||
if (props.Special)
|
||||
availableCharacters += this.SpecialCharacters;
|
||||
@@ -77,9 +83,9 @@ export default class Generator
|
||||
return availableCharacters;
|
||||
}
|
||||
|
||||
private static GetRequiredCharacters(props : GeneratorOptions) : string
|
||||
private static GetRequiredCharacters(props: GeneratorOptions): string
|
||||
{
|
||||
let requiredCharacters : string = "";
|
||||
let requiredCharacters: string = "";
|
||||
|
||||
if (props.Special)
|
||||
requiredCharacters += this.PickRandomFromArray(this.SpecialCharacters);
|
||||
@@ -100,12 +106,14 @@ export default class Generator
|
||||
|
||||
// See https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
// min is inclusive, max is exclusive
|
||||
private static GetRandomInt(min : number, max : number) : number
|
||||
private static GetRandomInt(min: number, max: number): number
|
||||
{
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
let arr = new Uint8Array(1);
|
||||
crypto.getRandomValues(arr);
|
||||
return Math.floor((arr[0] / 255) * (max - min)) + min;
|
||||
}
|
||||
|
||||
private static PickRandomFromArray(array : string) : string
|
||||
private static PickRandomFromArray(array: string): string
|
||||
{
|
||||
return array[this.GetRandomInt(0, array.length)];
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Storage } from "webextension-polyfill";
|
||||
import browser from "../Utils/Browser";
|
||||
|
||||
export default class GeneratorOptions
|
||||
{
|
||||
public Length: number = 16;
|
||||
@@ -11,34 +14,34 @@ export default class GeneratorOptions
|
||||
public ExcludeAmbiguous: boolean = true;
|
||||
public ExcludeRepeating: boolean = false;
|
||||
|
||||
public static OnChanged : (changes : Partial<GeneratorOptions>) => void;
|
||||
public static OnChanged: (changes: Partial<GeneratorOptions>) => void;
|
||||
|
||||
public static async Init() : Promise<GeneratorOptions>
|
||||
public static async Init(): Promise<GeneratorOptions>
|
||||
{
|
||||
let fallbackOptions : GeneratorOptions = new GeneratorOptions();
|
||||
let fallbackOptions: GeneratorOptions = new GeneratorOptions();
|
||||
|
||||
if (!chrome?.storage?.sync) // Extension is running as a standalone app
|
||||
if (!browser?.storage?.sync) // Extension is running as a standalone app
|
||||
return fallbackOptions;
|
||||
|
||||
let props : { [key: string]: any } = await chrome.storage.sync.get(fallbackOptions);
|
||||
let props: { [key: string]: any; } = await browser.storage.sync.get(fallbackOptions);
|
||||
|
||||
chrome.storage.sync.onChanged.addListener(GeneratorOptions.OnStorageChanged);
|
||||
browser.storage.sync.onChanged.addListener(GeneratorOptions.OnStorageChanged);
|
||||
|
||||
return props as GeneratorOptions;
|
||||
}
|
||||
|
||||
public static async Update(changes : Partial<GeneratorOptions>) : Promise<void>
|
||||
public static async Update(changes: Partial<GeneratorOptions>): Promise<void>
|
||||
{
|
||||
if (chrome?.storage?.sync)
|
||||
await chrome?.storage?.sync?.set(changes);
|
||||
if (browser?.storage?.sync)
|
||||
await browser?.storage?.sync?.set(changes);
|
||||
else
|
||||
GeneratorOptions.OnChanged(changes);
|
||||
}
|
||||
|
||||
private static OnStorageChanged(changes : { [key: string]: chrome.storage.StorageChange }) : void
|
||||
private static OnStorageChanged(changes: { [key: string]: Storage.StorageChange; }): void
|
||||
{
|
||||
let propsList : string[] = Object.keys(new GeneratorOptions());
|
||||
let options : { [key: string]: any } = { };
|
||||
let propsList: string[] = Object.keys(new GeneratorOptions());
|
||||
let options: { [key: string]: any; } = {};
|
||||
|
||||
Object.entries(changes)
|
||||
.filter(i => propsList.includes(i[0]))
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import browser from "../Utils/Browser";
|
||||
|
||||
export default class Localization
|
||||
{
|
||||
public static GetString(key : string) : string
|
||||
public static GetString(key: string): string
|
||||
{
|
||||
let sanitizedKey : string = key
|
||||
let sanitizedKey: string = key
|
||||
.replaceAll(".", "_")
|
||||
.replaceAll(",", "_")
|
||||
.replaceAll(" ", "_")
|
||||
@@ -10,13 +12,13 @@ export default class Localization
|
||||
.replaceAll("?", "_")
|
||||
.replaceAll("!", "_");
|
||||
|
||||
let str : string = chrome?.i18n?.getMessage(sanitizedKey);
|
||||
let str: string = browser?.i18n?.getMessage(sanitizedKey);
|
||||
|
||||
return str ?? key;
|
||||
}
|
||||
}
|
||||
|
||||
export function loc(key : string) : string
|
||||
export function loc(key: string): string
|
||||
{
|
||||
return Localization.GetString(key);
|
||||
}
|
||||
|
||||
+16
-13
@@ -1,36 +1,39 @@
|
||||
import { Storage } from "webextension-polyfill";
|
||||
import browser from "../Utils/Browser";
|
||||
|
||||
export default class Settings
|
||||
{
|
||||
public AddContext : boolean = true;
|
||||
public Autocopy : boolean = true;
|
||||
public AddContext: boolean = true;
|
||||
public Autocopy: boolean = true;
|
||||
|
||||
public static OnChanged : (changes : Partial<Settings>) => void;
|
||||
public static OnChanged: (changes: Partial<Settings>) => void;
|
||||
|
||||
public static async Init() : Promise<Settings>
|
||||
public static async Init(): Promise<Settings>
|
||||
{
|
||||
let fallbackOptions = new Settings();
|
||||
|
||||
if (!chrome?.storage?.sync)
|
||||
if (!browser?.storage?.sync)
|
||||
return fallbackOptions;
|
||||
|
||||
let props : { [key: string]: any } = await chrome.storage.sync.get(fallbackOptions);
|
||||
let props: { [key: string]: any; } = await browser.storage.sync.get(fallbackOptions);
|
||||
|
||||
chrome.storage.sync.onChanged.addListener(Settings.OnStorageChanged);
|
||||
browser.storage.sync.onChanged.addListener(Settings.OnStorageChanged);
|
||||
|
||||
return props as Settings;
|
||||
}
|
||||
|
||||
public static async Update(changes : Partial<Settings>) : Promise<void>
|
||||
public static async Update(changes: Partial<Settings>): Promise<void>
|
||||
{
|
||||
if (chrome?.storage?.sync)
|
||||
await chrome?.storage?.sync?.set(changes);
|
||||
if (browser?.storage?.sync)
|
||||
await browser?.storage?.sync?.set(changes);
|
||||
else
|
||||
Settings.OnChanged(changes);
|
||||
}
|
||||
|
||||
private static OnStorageChanged(changes : { [key: string]: chrome.storage.StorageChange }) : void
|
||||
private static OnStorageChanged(changes: { [key: string]: Storage.StorageChange; }): void
|
||||
{
|
||||
let propsList : string[] = Object.keys(new Settings());
|
||||
let settings : { [key: string]: any } = { };
|
||||
let propsList: string[] = Object.keys(new Settings());
|
||||
let settings: { [key: string]: any; } = {};
|
||||
|
||||
Object.entries(changes)
|
||||
.filter(i => propsList.includes(i[0]))
|
||||
|
||||
+5
-5
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"compilerOptions":
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib":
|
||||
[
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
@@ -23,5 +21,7 @@
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [ "src" ]
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user